summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java3
-rw-r--r--api/coverage/tools/ExtractFlaggedApis.kt2
-rw-r--r--api/coverage/tools/extract_flagged_apis.proto2
-rw-r--r--config/dirty-image-objects1985
-rw-r--r--core/api/current.txt3
-rw-r--r--core/api/module-lib-current.txt1
-rw-r--r--core/api/system-current.txt10
-rw-r--r--core/api/system-lint-baseline.txt2
-rw-r--r--core/java/android/app/Activity.java13
-rw-r--r--core/java/android/app/ApplicationPackageManager.java2
-rw-r--r--core/java/android/app/AutomaticZenRule.java4
-rw-r--r--core/java/android/app/FullscreenRequestHandler.java24
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java37
-rw-r--r--core/java/android/content/pm/ILauncherApps.aidl2
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/LauncherApps.java49
-rw-r--r--core/java/android/content/pm/PackageInstaller.java11
-rw-r--r--core/java/android/content/pm/PackageManager.java15
-rw-r--r--core/java/android/content/pm/SharedLibraryInfo.java82
-rw-r--r--core/java/android/hardware/biometrics/AuthenticationStateListener.aidl36
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java38
-rw-r--r--core/java/android/hardware/biometrics/BiometricRequestConstants.java (renamed from core/java/android/hardware/biometrics/BiometricOverlayConstants.java)25
-rw-r--r--core/java/android/hardware/biometrics/IAuthService.aidl7
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java1
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl9
-rw-r--r--core/java/android/nfc/NfcAdapter.java16
-rw-r--r--core/java/android/nfc/cardemulation/ApduServiceInfo.java20
-rw-r--r--core/java/android/service/voice/HotwordRejectedResult.java20
-rw-r--r--core/java/android/service/voice/flags/flags.aconfig7
-rw-r--r--core/java/android/view/WindowManager.java10
-rw-r--r--core/java/com/android/internal/app/SuspendedAppActivity.java11
-rw-r--r--core/java/com/android/internal/net/TEST_MAPPING2
-rw-r--r--core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java17
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java15
-rw-r--r--core/jni/android_util_Process.cpp40
-rw-r--r--core/res/res/values/attrs.xml11
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/public-staging.xml2
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/coretests/src/android/app/AutomaticZenRuleTest.java9
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java31
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java38
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java52
-rw-r--r--media/java/android/media/tv/ITvInputManager.aidl4
-rw-r--r--media/java/android/media/tv/ITvInputSession.aidl3
-rw-r--r--media/java/android/media/tv/ITvInputSessionWrapper.java21
-rw-r--r--media/java/android/media/tv/TvInputManager.java32
-rw-r--r--media/java/android/media/tv/TvInputService.java41
-rw-r--r--media/java/android/media/tv/TvView.java30
-rw-r--r--media/java/android/media/tv/ad/TvAdService.java8
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java25
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt37
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt1
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt9
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt58
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt2
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt31
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt26
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java26
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java76
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig7
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt11
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt83
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt94
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt22
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt65
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt42
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt80
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt76
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt109
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt19
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt10
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt28
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt4
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt44
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt171
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt14
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java42
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt30
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt91
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt72
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt89
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/CustomTilePackageUpdatesRepositoryTest.kt98
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml2
-rw-r--r--packages/SystemUI/res/layout/sidefps_view.xml2
-rw-r--r--packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt61
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt124
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt70
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SideFpsIndicatorView.kt (renamed from packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt)2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt112
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt224
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt229
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt54
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt176
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt173
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt484
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt84
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt576
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt238
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt39
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt34
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt11
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt24
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTilePackageUpdatesRepository.kt13
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt4
-rw-r--r--services/accessibility/Android.bp3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java1
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java6
-rw-r--r--services/autofill/bugfixes.aconfig2
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java5
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java6
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java20
-rw-r--r--services/core/java/com/android/server/BatteryService.java15
-rw-r--r--services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java30
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java3
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java3
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java21
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java12
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java108
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/EnrollClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java43
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java39
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java39
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java37
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java26
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java12
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java33
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java38
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerService.java31
-rw-r--r--services/core/java/com/android/server/devicestate/OverrideRequest.java13
-rw-r--r--services/core/java/com/android/server/devicestate/OverrideRequestController.java15
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java4
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java9
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig8
-rw-r--r--services/core/java/com/android/server/display/mode/DisplayModeDirector.java27
-rw-r--r--services/core/java/com/android/server/display/mode/Vote.java4
-rw-r--r--services/core/java/com/android/server/display/mode/VoteSummary.java12
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java10
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java55
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java22
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerInternal.java19
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java13
-rw-r--r--services/core/java/com/android/server/pm/BroadcastHelper.java13
-rw-r--r--services/core/java/com/android/server/pm/Computer.java4
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java17
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java6
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java3
-rw-r--r--services/core/java/com/android/server/pm/InstallRequest.java3
-rw-r--r--services/core/java/com/android/server/pm/KnownPackages.java4
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java29
-rw-r--r--services/core/java/com/android/server/pm/PackageArchiver.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerInternalBase.java19
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java48
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageRemovedInfo.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java5
-rw-r--r--services/core/java/com/android/server/pm/ReconcilePackageUtils.java33
-rw-r--r--services/core/java/com/android/server/pm/RemovePackageHelper.java175
-rw-r--r--services/core/java/com/android/server/pm/Settings.java38
-rw-r--r--services/core/java/com/android/server/pm/SuspendPackageHelper.java160
-rw-r--r--services/core/java/com/android/server/pm/UserTypeFactory.java1
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java30
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java3
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java23
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java3
-rw-r--r--services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java5
-rw-r--r--services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java5
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java40
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java15
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartInterceptor.java9
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java142
-rw-r--r--services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java20
-rw-r--r--services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java140
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java17
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt100
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt70
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java55
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java38
-rw-r--r--services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java50
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java53
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java2
-rw-r--r--telephony/java/android/telephony/CarrierRestrictionRules.java24
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java12
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java2
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl4
-rw-r--r--tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt3
299 files changed, 9336 insertions, 1778 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 12f455ad0144..bd5c00600044 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -2258,7 +2258,8 @@ public class AppStandbyController
}
synchronized (mSystemExemptionAppOpMode) {
if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- mSystemExemptionAppOpMode.delete(UserHandle.getUid(userId, getAppId(pkgName)));
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
+ mSystemExemptionAppOpMode.delete(uid);
}
}
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
index 43caaecebdaf..caa1929abd54 100644
--- a/api/coverage/tools/ExtractFlaggedApis.kt
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -43,7 +43,7 @@ fun main(args: Array<String>) {
.setClassName(it.fullName())
.setMethodName(method.name())
for (param in method.parameters()) {
- api.addParameterTypes(param.type().toTypeString())
+ api.addParameters(param.type().toTypeString())
}
if (builder.containsFlagToApi(flagValue)) {
var updatedApis =
diff --git a/api/coverage/tools/extract_flagged_apis.proto b/api/coverage/tools/extract_flagged_apis.proto
index 031d621b178f..4db2a8b03de5 100644
--- a/api/coverage/tools/extract_flagged_apis.proto
+++ b/api/coverage/tools/extract_flagged_apis.proto
@@ -32,6 +32,6 @@ message JavaMethod {
string package_name = 1;
string class_name = 2;
string method_name = 3;
- repeated string parameter_types = 4;
+ repeated string parameters = 4;
}
diff --git a/config/dirty-image-objects b/config/dirty-image-objects
index 2584610e2848..f2e2b82cd82a 100644
--- a/config/dirty-image-objects
+++ b/config/dirty-image-objects
@@ -16,282 +16,1713 @@
#
#
# Dirty-image-objects file for boot image.
-#
-# Objects in this file are known dirty at runtime. Current this includes:
-# - classes with known dirty static fields.
-#
# The image writer will bin these objects together in the image.
+# More info about dirty objects format and how to collect the data can be
+# found in: art/imgdiag/dirty_image_objects.md
+# This particular file was generated by dumping all pre-installed apps.
#
-# This file can be generated using imgdiag with a command such as:
-# adb shell imgdiag --image-diff-pid=<app pid> --zygote-diff-pid=<zygote pid> \
-# --boot-image=/system/framework/boot.art --dump-dirty-objects
-# Then, grep for lines containing "Private dirty object" from the output.
-# This particular file was generated by dumping systemserver and systemui.
-#
-Landroid/animation/LayoutTransition;
-Landroid/app/ActivityManager;
-Landroid/app/ActivityTaskManager;
-Landroid/app/ActivityThread;
-Landroid/app/AlarmManager;
-Landroid/app/AppOpsManager;
-Landroid/app/ContextImpl;
-Landroid/app/Notification;
-Landroid/app/NotificationManager;
-Landroid/app/PendingIntent$FinishedDispatcher;
-Landroid/app/PropertyInvalidatedCache$NoPreloadHolder;
-Landroid/app/QueuedWork;
-Landroid/app/ResourcesManager;
-Landroid/app/SystemServiceRegistry;
-Landroid/app/WallpaperManager;
-Landroid/app/backup/BackupManager;
-Landroid/compat/Compatibility;
-Landroid/content/AsyncQueryHandler;
-Landroid/content/ContentProviderClient;
-Landroid/content/ContentResolver;
-Landroid/content/Context;
-Landroid/content/pm/PackageItemInfo;
-Landroid/content/pm/UserPackage;
-Landroid/content/res/ResourceTimer;
-Landroid/database/CursorWindow;
-Landroid/database/sqlite/SQLiteCompatibilityWalFlags;
-Landroid/database/sqlite/SQLiteDebug$NoPreloadHolder;
-Landroid/database/sqlite/SQLiteGlobal;
-Landroid/ddm/DdmHandleAppName;
-Landroid/graphics/Bitmap;
-Landroid/graphics/Canvas;
-Landroid/graphics/Compatibility;
-Landroid/graphics/HardwareRenderer;
-Landroid/graphics/TemporaryBuffer;
-Landroid/graphics/Typeface;
-Landroid/graphics/drawable/AdaptiveIconDrawable;
-Landroid/hardware/SensorPrivacyManager;
-Landroid/hardware/SystemSensorManager;
-Landroid/hardware/devicestate/DeviceStateManagerGlobal;
-Landroid/hardware/display/ColorDisplayManager$ColorDisplayManagerInternal;
-Landroid/hardware/display/DisplayManagerGlobal;
-Landroid/hardware/input/InputManagerGlobal;
-Landroid/hardware/location/GeofenceHardwareImpl;
-Landroid/icu/impl/number/range/StandardPluralRanges;
-Landroid/icu/text/Collator;
-Landroid/icu/util/TimeZone;
-Landroid/location/LocationManager;
-Landroid/media/AudioManager;
-Landroid/media/AudioPlaybackConfiguration;
-Landroid/media/AudioSystem;
-Landroid/media/MediaCodec;
-Landroid/media/MediaCodecList;
-Landroid/media/MediaFrameworkPlatformInitializer;
-Landroid/media/MediaRouter2Manager;
-Landroid/media/MediaRouter;
-Landroid/media/PlayerBase;
-Landroid/media/audiopolicy/AudioProductStrategy;
-Landroid/media/audiopolicy/AudioVolumeGroup;
-Landroid/nfc/NfcAdapter;
-Landroid/nfc/NfcFrameworkInitializer;
-Landroid/nfc/cardemulation/CardEmulation;
-Landroid/os/AsyncTask;
-Landroid/os/BaseBundle;
-Landroid/os/Binder;
-Landroid/os/BinderProxy;
-Landroid/os/Environment;
-Landroid/os/FileObserver;
-Landroid/os/Handler;
-Landroid/os/LocaleList;
-Landroid/os/Looper;
-Landroid/os/Message;
-Landroid/os/NullVibrator;
-Landroid/os/Parcel;
-Landroid/os/Process;
-Landroid/os/ServiceManager;
-Landroid/os/StrictMode;
-Landroid/os/UEventObserver;
-Landroid/os/UserManager;
-Landroid/os/WorkSource;
-Landroid/os/storage/StorageManager;
-Landroid/permission/PermissionManager;
-Landroid/provider/DeviceConfigInitializer;
-Landroid/provider/FontsContract;
-Landroid/provider/Settings;
-Landroid/renderscript/RenderScript;
-Landroid/renderscript/RenderScriptCacheDir;
-Landroid/security/keystore2/KeyStoreCryptoOperationUtils;
-Landroid/security/net/config/ApplicationConfig;
-Landroid/security/net/config/SystemCertificateSource$NoPreloadHolder;
-Landroid/security/net/config/UserCertificateSource$NoPreloadHolder;
-Landroid/telecom/Log;
-Landroid/telecom/TelecomManager;
-Landroid/telephony/AnomalyReporter;
-Landroid/telephony/TelephonyFrameworkInitializer;
-Landroid/telephony/TelephonyLocalConnection;
-Landroid/telephony/TelephonyManager;
-Landroid/telephony/TelephonyRegistryManager;
-Landroid/text/DynamicLayout;
-Landroid/text/TextUtils;
-Landroid/text/format/DateFormat;
-Landroid/text/format/DateUtils;
-Landroid/text/method/ArrowKeyMovementMethod;
-Landroid/text/method/LinkMovementMethod;
-Landroid/text/method/SingleLineTransformationMethod;
-Landroid/text/style/ClickableSpan;
-Landroid/timezone/TelephonyLookup;
-Landroid/timezone/TimeZoneFinder;
-Landroid/util/ArrayMap;
-Landroid/util/ArraySet;
-Landroid/util/EventLog;
-Landroid/util/NtpTrustedTime;
-Landroid/view/Choreographer;
-Landroid/view/CrossWindowBlurListeners;
-Landroid/view/DisplayCutout;
-Landroid/view/KeyEvent;
-Landroid/view/MotionEvent;
-Landroid/view/PointerIcon;
-Landroid/view/RoundedCorners;
-Landroid/view/SurfaceControl;
-Landroid/view/View;
-Landroid/view/ViewGroup$TouchTarget;
-Landroid/view/ViewRootImpl;
-Landroid/view/ViewTreeObserver;
-Landroid/view/WindowManagerGlobal;
-Landroid/view/accessibility/AccessibilityManager;
-Landroid/view/accessibility/AccessibilityNodeIdManager;
-Landroid/view/autofill/Helper;
-Landroid/view/inputmethod/IInputMethodManagerGlobalInvoker;
-Landroid/view/inputmethod/InputMethodManager;
-Landroid/webkit/CookieSyncManager;
-Landroid/webkit/WebView;
-Landroid/webkit/WebViewFactory;
-Landroid/webkit/WebViewZygote;
-Landroid/widget/AbsListView;
-Landroid/widget/ImageView;
-Landroid/widget/LinearLayout;
-Landroid/widget/Toast;
-Landroid/window/SurfaceSyncGroup;
-Lcom/android/i18n/timezone/TelephonyLookup;
-Lcom/android/i18n/timezone/TimeZoneFinder;
-Lcom/android/internal/config/appcloning/AppCloningDeviceConfigHelper;
-Lcom/android/internal/content/om/OverlayConfig;
-Lcom/android/internal/display/BrightnessSynchronizer;
-Lcom/android/internal/infra/AndroidFuture;
-Lcom/android/internal/inputmethod/ImeTracing;
-Lcom/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry;
-Lcom/android/internal/jank/InteractionJankMonitor$InstanceHolder;
-Lcom/android/internal/jank/InteractionJankMonitor;
-Lcom/android/internal/logging/MetricsLogger;
-Lcom/android/internal/os/BackgroundThread;
-Lcom/android/internal/os/BinderInternal;
-Lcom/android/internal/os/KernelCpuBpfTracking;
-Lcom/android/internal/os/RuntimeInit;
-Lcom/android/internal/os/SomeArgs;
-Lcom/android/internal/os/ZygoteInit;
-Lcom/android/internal/policy/AttributeCache;
-Lcom/android/internal/protolog/BaseProtoLogImpl;
-Lcom/android/internal/protolog/ProtoLogImpl;
-Lcom/android/internal/statusbar/NotificationVisibility;
-Lcom/android/internal/telephony/CellBroadcastServiceManager;
-Lcom/android/internal/telephony/IntentBroadcaster;
-Lcom/android/internal/telephony/MccTable;
-Lcom/android/internal/telephony/MultiSimSettingController;
-Lcom/android/internal/telephony/PackageChangeReceiver;
-Lcom/android/internal/telephony/PhoneConfigurationManager;
-Lcom/android/internal/telephony/PhoneFactory;
-Lcom/android/internal/telephony/ProxyController;
-Lcom/android/internal/telephony/RILRequest;
-Lcom/android/internal/telephony/RadioConfig;
-Lcom/android/internal/telephony/RadioInterfaceCapabilityController;
-Lcom/android/internal/telephony/SmsApplication;
-Lcom/android/internal/telephony/SmsBroadcastUndelivered;
-Lcom/android/internal/telephony/SomeArgs;
-Lcom/android/internal/telephony/TelephonyComponentFactory;
-Lcom/android/internal/telephony/TelephonyDevController;
-Lcom/android/internal/telephony/cat/CatService;
-Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler;
-Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;
-Lcom/android/internal/telephony/euicc/EuiccCardController;
-Lcom/android/internal/telephony/euicc/EuiccController;
-Lcom/android/internal/telephony/ims/ImsResolver;
-Lcom/android/internal/telephony/metrics/TelephonyMetrics;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$CarrierIdMismatch;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$CellularDataServiceSwitch;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$CellularServiceState;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$DataCallSession;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$EmergencyNumbersInfo;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$GbaEvent;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsDedicatedBearerEvent;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsDedicatedBearerListenerEvent;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationFeatureTagStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationServiceDescStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationTermination;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$IncomingSms;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$NetworkRequests;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$NetworkRequestsV2;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$OutgoingShortCodeSms;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$OutgoingSms;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$PresenceNotifyEvent;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$RcsAcsProvisioningStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$RcsClientProvisioningStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteController;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteIncomingDatagram;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteOutgoingDatagram;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteProvision;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteSession;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteSosMessageRecommender;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SipDelegateStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SipMessageResponse;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SipTransportFeatureTagStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SipTransportSession;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$UceEventStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$UnmeteredNetworks;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$VoiceCallRatUsage;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$VoiceCallSession;
-Lcom/android/internal/telephony/nano/TelephonyProto$RilDataCall;
-Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyCallSession$Event$RilCall;
-Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyServiceState$NetworkRegistrationInfo;
-Lcom/android/internal/telephony/satellite/PointingAppController;
-Lcom/android/internal/telephony/satellite/SatelliteModemInterface;
-Lcom/android/internal/telephony/uicc/UiccController;
-Lcom/android/internal/telephony/uicc/UiccStateChangedLauncher;
-Lcom/android/internal/util/ContrastColorUtil;
-Lcom/android/internal/view/WindowManagerPolicyThread;
-Lcom/android/org/bouncycastle/crypto/CryptoServicesRegistrar;
-Lcom/android/phone/ecc/nano/ProtobufEccData$CountryInfo;
-Lcom/android/phone/ecc/nano/ProtobufEccData$EccInfo;
-Lcom/android/server/AppWidgetBackupBridge;
-Ldalvik/system/BaseDexClassLoader;
-Ldalvik/system/BlockGuard;
-Ldalvik/system/CloseGuard;
-Ldalvik/system/RuntimeHooks;
-Ldalvik/system/SocketTagger;
-Ldalvik/system/VMRuntime;
-Ldalvik/system/ZipPathValidator;
-Ldalvik/system/ZygoteHooks;
-Ljava/lang/System;
-Ljava/lang/Thread;
-Ljava/lang/Throwable;
-Ljava/lang/ref/FinalizerReference;
-Ljava/lang/ref/ReferenceQueue;
-Ljava/net/ResponseCache;
-Ljava/nio/Bits;
-Ljava/nio/charset/Charset;
-Ljava/security/Provider;
-Ljava/util/Collections;
-Ljava/util/GregorianCalendar;
-Ljava/util/Locale$NoImagePreloadHolder;
-Ljava/util/Locale;
-Ljava/util/Scanner;
-Ljava/util/TimeZone;
-Ljava/util/concurrent/ForkJoinPool;
-Ljava/util/concurrent/ThreadLocalRandom;
-Ljavax/net/ServerSocketFactory;
-Ljavax/net/SocketFactory;
-Ljavax/net/ssl/HttpsURLConnection$NoPreloadHolder;
-Ljavax/net/ssl/HttpsURLConnection;
-Ljavax/net/ssl/SSLContext;
-Ljavax/net/ssl/SSLServerSocketFactory;
-Ljavax/net/ssl/SSLSocketFactory;
-Llibcore/io/Libcore;
-Llibcore/net/NetworkSecurityPolicy;
-Lsun/misc/Cleaner;
-Lsun/nio/ch/FileChannelImpl$Unmapper;
-Lsun/nio/ch/FileChannelImpl;
-Lsun/security/jca/Providers;
+Landroid/text/style/URLSpan; 0
+Landroid/content/res/Resources$NotFoundException; 1
+Landroid/os/PowerManager$WakeLock; 2
+Landroid/os/BatterySaverPolicyConfig; 2
+Landroid/content/ContextWrapper; 2
+Landroid/app/WallpaperInfo; 2
+Landroid/content/pm/PackageManager; 2
+Landroid/app/IWallpaperManager; 2
+Ljava/lang/BootClassLoader; 2
+Ljava/time/Duration; 2
+Landroid/util/Printer; 2
+Landroid/app/WallpaperManager$OnColorsChangedListener; 2
+Landroid/app/WallpaperColors; 2
+Landroid/content/pm/ServiceInfo; 2
+Landroid/app/KeyguardManager$KeyguardDismissCallback; 2
+Ljava/lang/CharSequence; 3
+Landroid/widget/Switch; 4
+Lcom/android/internal/util/ContrastColorUtil; 4
+Landroid/view/SurfaceControl; 4
+Landroid/graphics/ColorMatrix;.dexCache:Ljava/lang/Object; 4
+Lcom/android/internal/widget/CachingIconView; 4
+Landroid/window/IRemoteTransition$Stub$Proxy; 4
+Landroid/app/trust/TrustManager$TrustListener; 4
+Landroid/view/NotificationHeaderView; 4
+Lcom/android/internal/widget/ImageResolver; 4
+Landroid/window/WindowContainerTransaction$Change; 4
+Lcom/android/internal/widget/MessagingLayout; 4
+Ljava/util/concurrent/ConcurrentLinkedQueue; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry; 4
+Landroid/view/RemotableViewMethod; 4
+Landroid/app/IApplicationThread$Stub$Proxy; 4
+Landroid/os/FileUtils; 4
+Landroid/view/View;.SCALE_X:Landroid/util/Property; 4
+Landroid/widget/GridLayout;.UNDEFINED_ALIGNMENT:Landroid/widget/GridLayout$Alignment; 4
+Landroid/media/MediaPlayer$EventHandler; 4
+Landroid/widget/DateTimeView; 4
+Llibcore/util/ZoneInfo; 4
+Lcom/android/internal/statusbar/IStatusBarService; 4
+Ljava/lang/invoke/MethodType;.internTable:Ljava/lang/invoke/MethodType$ConcurrentWeakInternSet;.stale:Ljava/lang/ref/ReferenceQueue; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry; 4
+Lcom/android/internal/logging/UiEventLogger; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry; 4
+Landroid/renderscript/RenderScript; 4
+Landroid/view/ViewTreeObserver$OnWindowVisibilityChangeListener; 4
+Lcom/android/internal/widget/RemeasuringLinearLayout; 4
+Landroid/widget/DateTimeView$ReceiverInfo$1; 4
+Landroid/view/View;.TRANSLATION_Y:Landroid/util/Property; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry; 4
+Lcom/android/internal/widget/NotificationExpandButton; 4
+Lcom/android/internal/view/menu/ActionMenuItemView; 4
+Landroid/view/animation/AnimationSet; 4
+Landroid/hardware/biometrics/BiometricSourceType;.FINGERPRINT:Landroid/hardware/biometrics/BiometricSourceType; 4
+Landroid/window/WindowOrganizer;.IWindowOrganizerControllerSingleton:Landroid/util/Singleton; 4
+Ljava/lang/Runnable; 4
+Lorg/apache/harmony/dalvik/ddmc/DdmServer;.mHandlerMap:Ljava/util/HashMap; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry; 4
+Lcom/android/internal/widget/ImageFloatingTextView; 4
+Landroid/window/IWindowContainerToken$Stub$Proxy; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry; 4
+Landroid/content/res/ColorStateList; 4
+Landroid/view/View;.SCALE_Y:Landroid/util/Property; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap; 4
+Lcom/android/internal/widget/ConversationLayout; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry; 4
+Lcom/android/internal/colorextraction/ColorExtractor$OnColorsChangedListener; 4
+Landroid/hardware/face/FaceManager$FaceDetectionCallback; 4
+Landroid/widget/RemoteViews;.sLookupKey:Landroid/widget/RemoteViews$MethodKey; 4
+Landroid/widget/ViewSwitcher;.dexCache:Ljava/lang/Object; 4
+Lcom/android/internal/widget/NotificationActionListLayout; 4
+Ljava/util/concurrent/ConcurrentLinkedQueue$Node; 4
+Landroid/hardware/biometrics/BiometricSourceType;.FACE:Landroid/hardware/biometrics/BiometricSourceType; 4
+Landroid/hardware/biometrics/BiometricSourceType;.IRIS:Landroid/hardware/biometrics/BiometricSourceType; 4
+Landroid/view/NotificationTopLineView; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry; 4
+Landroid/widget/RemoteViews;.sMethods:Landroid/util/ArrayMap; 4
+Lcom/android/internal/os/BinderInternal$BinderProxyLimitListener; 5
+Landroid/app/AppOpsManager$OnOpNotedInternalListener; 5
+Lcom/android/internal/R$styleable;.WindowAnimation:[I 5
+Lcom/android/internal/logging/UiEventLogger$UiEventEnum; 5
+Lcom/android/internal/policy/AttributeCache; 5
+Landroid/app/Notification$CallStyle; 5
+Landroid/app/AppOpsManager$OnOpNotedListener; 5
+Lcom/android/internal/protolog/BaseProtoLogImpl; 5
+Landroid/app/AppOpsManager$OnOpStartedListener; 5
+Lcom/android/internal/util/ScreenshotHelper$1; 5
+Landroid/app/Notification$DecoratedCustomViewStyle; 5
+Landroid/view/DisplayCutout; 5
+Landroid/view/InputEvent;.mNextSeq:Ljava/util/concurrent/atomic/AtomicInteger; 5
+Lcom/android/internal/statusbar/NotificationVisibility; 5
+Landroid/telephony/DataSpecificRegistrationInfo; 6
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle; 7
+Landroid/telephony/VoiceSpecificRegistrationInfo; 8
+Landroid/telephony/AnomalyReporter; 8
+Landroid/telephony/TelephonyRegistryManager;.sCarrierPrivilegeCallbacks:Ljava/util/WeakHashMap; 8
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.1:Ljava/util/WeakHashMap$Entry; 8
+Landroid/app/LoadedApk$ServiceDispatcher$InnerConnection; 8
+Landroid/content/ContentProvider$Transport; 8
+Landroid/telephony/NetworkRegistrationInfo; 8
+Landroid/net/MatchAllNetworkSpecifier; 8
+Landroid/telephony/TelephonyRegistryManager;.sCarrierPrivilegeCallbacks:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry; 8
+Landroid/app/PropertyInvalidatedCache;.sInvalidates:Ljava/util/HashMap; 9
+Landroid/app/PropertyInvalidatedCache$NoPreloadHolder; 9
+Landroid/app/PropertyInvalidatedCache;.sDisabledKeys:Ljava/util/HashSet;.map:Ljava/util/HashMap; 10
+Landroid/media/AudioSystem$AudioRecordingCallback; 11
+Lcom/android/internal/util/Parcelling$BuiltIn$ForInternedString; 11
+Landroid/net/metrics/IpManagerEvent; 11
+Lcom/android/internal/os/ProcessCpuTracker$FilterStats; 11
+Lcom/android/internal/infra/AbstractRemoteService$AsyncRequest; 11
+Landroid/content/pm/RegisteredServicesCache$3; 11
+Lcom/android/internal/os/LooperStats; 11
+Lcom/android/server/AppWidgetBackupBridge; 11
+Landroid/hardware/display/DisplayManagerInternal; 11
+Landroid/content/pm/PackageInfo; 11
+Landroid/hardware/soundtrigger/SoundTriggerModule$EventHandlerDelegate; 11
+Landroid/app/servertransaction/ResumeActivityItem; 11
+Lcom/android/internal/widget/AlertDialogLayout; 11
+Landroid/content/pm/FallbackCategoryProvider;.sFallbacks:Landroid/util/ArrayMap; 11
+Landroid/os/RemoteCallback$1; 11
+Landroid/content/pm/SharedLibraryInfo; 11
+Landroid/util/MemoryIntArray; 11
+Landroid/net/metrics/DhcpErrorEvent; 11
+Lcom/android/internal/util/function/DodecConsumer; 11
+Landroid/provider/Settings; 11
+Landroid/app/PropertyInvalidatedCache;.sCorkLock:Ljava/lang/Object; 11
+Lcom/android/internal/os/CachedDeviceState$Readonly; 11
+Landroid/app/job/JobServiceEngine$JobHandler; 11
+Landroid/app/SystemServiceRegistry; 11
+Lcom/android/internal/os/BinderInternal$CallStatsObserver; 11
+Lcom/android/internal/statusbar/IStatusBar$Stub$Proxy; 11
+Landroid/hardware/location/IActivityRecognitionHardwareClient; 11
+Landroid/telecom/Logging/EventManager$EventListener; 11
+Landroid/accounts/AccountManagerInternal; 11
+Lcom/android/internal/os/KernelCpuBpfTracking; 11
+Lcom/android/internal/statusbar/NotificationVisibility$NotificationLocation; 11
+Landroid/hardware/camera2/CameraManager$CameraManagerGlobal; 11
+Landroid/os/ServiceSpecificException; 11
+Landroid/net/Uri$PathPart;.NULL:Landroid/net/Uri$PathPart; 11
+Landroid/app/ActivityManagerInternal; 11
+Landroid/media/AudioSystem; 11
+Landroid/service/dreams/DreamManagerInternal; 11
+Landroid/debug/AdbManagerInternal; 11
+Landroid/graphics/Bitmap$CompressFormat; 11
+Landroid/hardware/location/NanoAppMessage; 11
+Landroid/os/storage/StorageManagerInternal; 11
+Landroid/app/AppOpsManagerInternal; 11
+Ljava/security/cert/CertificateException; 11
+Ldalvik/system/VMRuntime; 11
+Landroid/content/pm/SigningInfo; 11
+Landroid/view/KeyEvent; 11
+Lcom/android/internal/view/WindowManagerPolicyThread; 11
+Landroid/graphics/Region;.sPool:Landroid/util/Pools$SynchronizedPool;.mPool:[Ljava/lang/Object; 11
+Landroid/content/res/ResourceTimer; 11
+Landroid/view/autofill/AutofillManagerInternal; 11
+Lcom/android/internal/util/Parcelling$Cache;.sCache:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object; 11
+Landroid/graphics/Region;.sPool:Landroid/util/Pools$SynchronizedPool; 11
+Landroid/app/LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0; 11
+Lcom/android/server/LocalServices;.sLocalServiceObjects:Landroid/util/ArrayMap; 11
+Landroid/app/admin/DevicePolicyManagerInternal$OnCrossProfileWidgetProvidersChangeListener; 11
+Landroid/accounts/AccountManagerInternal$OnAppPermissionChangeListener; 11
+Landroid/content/pm/PermissionInfo; 11
+Landroid/view/WindowManagerPolicyConstants$PointerEventListener; 11
+Landroid/os/UEventObserver; 11
+Landroid/media/AudioManagerInternal$RingerModeDelegate; 11
+Landroid/view/Display$HdrCapabilities; 11
+Landroid/service/notification/Condition; 11
+Landroid/content/pm/UserPackage; 11
+Landroid/app/AppOpsManager$SamplingStrategy; 11
+Landroid/telephony/ServiceState; 11
+Landroid/app/servertransaction/PauseActivityItem; 11
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;.sMessageCallbacksPool:Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool;.mLock:Ljava/lang/Object; 11
+Landroid/view/KeyCharacterMap$FallbackAction; 11
+Lcom/android/internal/util/Parcelling$BuiltIn$ForInternedStringArray; 11
+Landroid/hardware/display/DeviceProductInfo; 11
+Lcom/android/internal/util/Parcelling$Cache;.sCache:Landroid/util/ArrayMap;.mHashes:[I 11
+Landroid/content/pm/RegisteredServicesCache$2; 11
+Landroid/content/pm/PackageManager;.sCacheAutoCorker:Landroid/app/PropertyInvalidatedCache$AutoCorker; 11
+Landroid/app/PropertyInvalidatedCache;.sCorks:Ljava/util/HashMap; 11
+Landroid/service/notification/StatusBarNotification; 11
+Landroid/app/servertransaction/ConfigurationChangeItem; 11
+Landroid/app/ActivityManager$RecentTaskInfo; 11
+Landroid/app/Notification; 11
+Landroid/app/servertransaction/DestroyActivityItem; 11
+Landroid/webkit/WebViewLibraryLoader$RelroFileCreator; 11
+Landroid/net/metrics/NetworkEvent; 11
+Landroid/media/AudioPlaybackConfiguration; 11
+Landroid/accessibilityservice/AccessibilityServiceInfo; 11
+Landroid/hardware/display/DeviceProductInfo$ManufactureDate; 11
+Landroid/os/storage/StorageVolume; 11
+Landroid/os/BatteryManagerInternal; 11
+Landroid/appwidget/AppWidgetManagerInternal; 11
+Landroid/app/servertransaction/NewIntentItem; 11
+Landroid/content/pm/ShortcutServiceInternal; 11
+Landroid/app/assist/ActivityId; 11
+Landroid/window/DisplayAreaAppearedInfo; 11
+Landroid/os/Process;.ZYGOTE_PROCESS:Landroid/os/ZygoteProcess;.mLock:Ljava/lang/Object; 11
+Landroid/app/usage/UsageStats; 11
+Landroid/app/Notification$MediaStyle; 11
+Landroid/media/AudioSystem$DynamicPolicyCallback; 11
+Landroid/content/pm/ProviderInfo; 11
+Landroid/os/PowerManagerInternal; 11
+Landroid/service/voice/VoiceInteractionManagerInternal; 11
+Landroid/content/pm/FeatureInfo; 11
+Landroid/app/servertransaction/TopResumedActivityChangeItem; 11
+Landroid/app/Notification$DecoratedMediaCustomViewStyle; 11
+Landroid/appwidget/AppWidgetProviderInfo; 11
+Landroid/app/AppOpsManager$NoteOpEvent; 11
+Landroid/graphics/GraphicsStatsService; 11
+Landroid/view/DisplayAddress$Physical; 11
+Landroid/content/ComponentName$WithComponentName; 11
+Landroid/app/admin/DevicePolicyManagerInternal; 11
+Landroid/os/ResultReceiver$MyResultReceiver; 11
+Landroid/content/ContentProviderClient; 11
+Landroid/content/pm/RegisteredServicesCache$1; 11
+Landroid/app/PendingIntent$FinishedDispatcher; 11
+Landroid/location/LocationManager; 11
+Landroid/hardware/location/ContextHubInfo; 11
+Landroid/content/pm/ShortcutServiceInternal$ShortcutChangeListener; 11
+Lcom/android/server/usage/AppStandbyInternal; 11
+Landroid/content/pm/RegisteredServicesCacheListener; 11
+Landroid/app/servertransaction/LaunchActivityItem; 11
+Landroid/content/pm/BaseParceledListSlice$1; 11
+Landroid/annotation/StringRes; 11
+Lcom/android/internal/R$styleable;.Window:[I 11
+Landroid/service/notification/ZenModeConfig; 11
+Landroid/telecom/Logging/SessionManager$ISessionListener; 11
+Landroid/app/time/TimeZoneConfiguration; 11
+Landroid/net/metrics/ValidationProbeEvent; 11
+Landroid/content/pm/PackageInstaller$SessionInfo; 11
+Landroid/content/pm/UserPackage;.sCache:Landroid/util/SparseArrayMap;.mData:Landroid/util/SparseArray; 11
+Landroid/content/pm/PermissionGroupInfo; 11
+Landroid/hardware/sidekick/SidekickInternal; 11
+Lcom/android/internal/widget/ButtonBarLayout; 11
+Landroid/content/pm/LauncherActivityInfoInternal; 11
+Lcom/android/internal/util/Parcelling$Cache;.sCache:Landroid/util/ArrayMap; 11
+Lcom/android/internal/widget/LockSettingsInternal; 11
+Landroid/media/AudioManagerInternal; 11
+Landroid/app/AppOpsManager$AttributedOpEntry; 11
+Lcom/android/internal/util/Parcelling$BuiltIn$ForInternedStringList; 11
+Landroid/telecom/Log; 11
+Landroid/app/time/TimeZoneCapabilities; 11
+Landroid/attention/AttentionManagerInternal; 11
+Landroid/view/WindowManagerPolicyConstants; 11
+Landroid/content/pm/CrossProfileAppsInternal; 11
+Landroid/hardware/location/GeofenceHardwareService; 11
+Landroid/content/pm/dex/ArtManagerInternal; 11
+Landroid/net/metrics/IpReachabilityEvent; 11
+Landroid/content/pm/LauncherApps$ShortcutQuery$QueryFlags; 11
+Landroid/media/AudioAttributes; 11
+Landroid/app/PropertyInvalidatedCache$AutoCorker$1; 11
+Landroid/net/metrics/ApfProgramEvent; 11
+Landroid/content/pm/SigningDetails; 11
+Lcom/android/internal/protolog/ProtoLogImpl; 11
+Landroid/hardware/biometrics/ComponentInfoInternal; 11
+Lcom/android/internal/util/ToBooleanFunction; 11
+Landroid/app/ActivityThread$H; 11
+Landroid/hardware/location/GeofenceHardwareImpl; 11
+Landroid/net/wifi/nl80211/WifiNl80211Manager$ScanEventHandler; 11
+Landroid/util/NtpTrustedTime; 11
+Landroid/hardware/soundtrigger/SoundTrigger$StatusListener; 11
+Lcom/android/internal/app/procstats/AssociationState;.sTmpSourceKey:Lcom/android/internal/app/procstats/AssociationState$SourceKey; 11
+Ljava/util/zip/ZipFile$ZipFileInflaterInputStream; 11
+Landroid/app/job/JobInfo; 11
+Lcom/android/internal/content/om/OverlayConfig; 11
+Landroid/webkit/WebViewZygote; 11
+Lcom/android/internal/util/Parcelling$BuiltIn$ForInternedStringSet; 11
+Lcom/android/internal/infra/AbstractRemoteService$VultureCallback; 11
+Landroid/permission/PermissionManagerInternal; 11
+Lcom/android/server/WidgetBackupProvider; 11
+Landroid/window/WindowOnBackInvokedDispatcher$OnBackInvokedCallbackWrapper; 11
+Landroid/app/PropertyInvalidatedCache;.sCorkedInvalidates:Ljava/util/HashMap; 11
+Landroid/media/AudioPlaybackConfiguration$PlayerDeathMonitor; 11
+Landroid/net/wifi/nl80211/WifiNl80211Manager$ScanEventCallback; 11
+Landroid/service/notification/NotificationListenerService$RankingMap; 11
+Landroid/os/UserHandle;.sExtraUserHandleCache:Landroid/util/SparseArray; 11
+Ljava/time/DateTimeException; 11
+Ljava/lang/NumberFormatException; 11
+Ljava/security/Provider;.knownEngines:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.125:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 11
+Landroid/app/LoadedApk$ServiceDispatcher$RunConnection; 11
+Landroid/view/RoundedCorners; 11
+Landroid/os/Process;.ZYGOTE_PROCESS:Landroid/os/ZygoteProcess; 11
+Landroid/media/audiopolicy/AudioVolumeGroup; 11
+Landroid/media/AudioSystem$ErrorCallback; 11
+Landroid/app/servertransaction/ActivityResultItem; 11
+Lcom/android/internal/widget/DialogTitle; 11
+Lcom/android/internal/os/StoragedUidIoStatsReader$Callback; 11
+Landroid/view/ViewRootImpl$W; 11
+Landroid/app/ServiceStartArgs; 11
+Landroid/window/TaskAppearedInfo; 11
+Lcom/android/internal/listeners/ListenerExecutor$FailureCallback; 11
+Landroid/app/ApplicationExitInfo; 11
+Landroid/content/pm/PackageManager;.sCacheAutoCorker:Landroid/app/PropertyInvalidatedCache$AutoCorker;.mLock:Ljava/lang/Object; 11
+Lcom/android/internal/util/Parcelling$BuiltIn$ForInternedStringValueMap; 11
+Landroid/content/pm/ResolveInfo; 11
+Lcom/android/internal/display/BrightnessSynchronizer; 11
+Landroid/window/IOnBackInvokedCallback$Stub$Proxy; 12
+Landroid/graphics/drawable/PictureDrawable; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.126:Ljava/lang/Byte; 13
+Landroid/view/ViewDebug$ExportedProperty; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.41:Ljava/lang/Byte; 13
+Landroid/view/inputmethod/DeleteGesture; 13
+Landroid/view/ViewDebug$IntToString; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.56:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.65:Ljava/lang/Byte; 13
+Landroid/webkit/WebViewFactory;.sProviderLock:Ljava/lang/Object; 13
+Ljava/lang/IllegalAccessError; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.51:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.52:Ljava/lang/Byte; 13
+Landroid/view/inputmethod/DeleteRangeGesture; 13
+Landroid/window/WindowContext; 13
+Ljava/util/concurrent/ConcurrentSkipListMap$Node; 13
+Landroid/view/inputmethod/SelectRangeGesture; 13
+Landroid/util/MalformedJsonException; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.131:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.120:Ljava/lang/Byte; 13
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 13
+Ljava/nio/file/StandardOpenOption;.TRUNCATE_EXISTING:Ljava/nio/file/StandardOpenOption; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.121:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.16:Ljava/lang/Byte; 13
+Ljava/util/concurrent/ConcurrentSkipListMap$Index; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.139:Ljava/lang/Byte; 13
+Landroid/view/ViewDebug$FlagToString; 13
+Landroid/view/inputmethod/SelectGesture; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.20:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.94:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.64:Ljava/lang/Byte; 13
+Landroid/webkit/WebViewFactoryProvider$Statics; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.95:Ljava/lang/Byte; 13
+Landroid/service/media/MediaBrowserService$ServiceBinder$1; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.7:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.23:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.46:Ljava/lang/Byte; 13
+Landroid/provider/Settings$SettingNotFoundException; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.74:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.8:Ljava/lang/Byte; 13
+Landroid/widget/TextView;.TEMP_POSITION:[F 13
+Ljava/io/ByteArrayInputStream; 14
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.93:Ljava/lang/Byte; 14
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.134:Ljava/lang/Byte; 14
+Landroid/text/style/ImageSpan; 14
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.154:Ljava/lang/Byte; 15
+Landroid/view/TextureView$SurfaceTextureListener; 16
+Landroid/media/AudioManager$OnAudioFocusChangeListener; 17
+Ljava/util/Locale;.JAPAN:Ljava/util/Locale; 18
+Ljava/util/Locale;.GERMANY:Ljava/util/Locale; 19
+Ljava/util/Locale;.CANADA_FRENCH:Ljava/util/Locale; 20
+Ljava/util/Locale;.ITALY:Ljava/util/Locale; 20
+Ljava/util/Locale;.FRANCE:Ljava/util/Locale; 20
+Ljava/util/Locale;.UK:Ljava/util/Locale; 21
+Ljava/util/Locale;.CANADA:Ljava/util/Locale; 21
+Ljava/util/Locale$Cache;.LOCALECACHE:Ljava/util/Locale$Cache;.map:Ljava/util/concurrent/ConcurrentMap; 22
+Ljava/lang/IllegalStateException; 23
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;.sMessageCallbacksPool:Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool; 24
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;.sMessageCallbacksPool:Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool;.mPool:[Ljava/lang/Object; 24
+Landroid/media/MediaRouter$WifiDisplayStatusChangedReceiver; 25
+Landroid/media/MediaRouter$VolumeChangeReceiver; 25
+Landroid/app/AppOpsManager$OnOpActiveChangedListener; 26
+Landroid/media/PlayerBase; 27
+Landroid/content/pm/Checksum$Type; 28
+Ljava/lang/Class; 29
+Landroid/widget/MediaController$MediaPlayerControl; 30
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.135:Ljava/lang/Long; 30
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.152:Ljava/lang/Long; 30
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.215:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.206:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.137:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.203:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.213:Ljava/lang/Byte; 31
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.549:Ljava/lang/Long; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.201:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.249:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.163:Ljava/lang/Byte; 31
+Ljava/util/HashMap; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.210:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.161:Ljava/lang/Byte; 31
+Landroid/icu/text/MeasureFormat;.hmsTo012:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.0:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.199:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.248:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.252:Ljava/lang/Byte; 31
+Lcom/android/ims/rcs/uce/UceDeviceState;.DEVICE_STATE_DESCRIPTION:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.3:Ljava/util/HashMap$Node;.key:Ljava/lang/Object; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.159:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.217:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.200:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.240:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.198:Ljava/lang/Byte; 31
+Lcom/android/ims/rcs/uce/UceDeviceState;.DEVICE_STATE_DESCRIPTION:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.4:Ljava/util/HashMap$Node;.key:Ljava/lang/Object; 31
+Landroid/content/pm/PackageManager$OnChecksumsReadyListener; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.193:Ljava/lang/Byte; 31
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.228:Ljava/lang/Long; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.236:Ljava/lang/Byte; 31
+Landroid/telephony/ims/ImsService;.CAPABILITIES_LOG_MAP:Ljava/util/Map;.table:[Ljava/lang/Object;.2:Ljava/lang/Long; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.211:Ljava/lang/Byte; 31
+Landroid/view/SurfaceView; 32
+Landroid/view/ViewStub$OnInflateListener; 33
+Landroid/graphics/drawable/DrawableInflater;.CONSTRUCTOR_MAP:Ljava/util/HashMap; 34
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.245:Ljava/lang/Byte; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.232:Ljava/lang/Byte; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.12:Ljava/lang/Byte; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.170:Ljava/lang/Long; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.183:Ljava/lang/Long; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.246:Ljava/lang/Byte; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.168:Ljava/lang/Long; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.72:Ljava/lang/Byte; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.243:Ljava/lang/Byte; 35
+Ljava/util/WeakHashMap;.NULL_KEY:Ljava/lang/Object; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.235:Ljava/lang/Byte; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.147:Ljava/lang/Long; 35
+Ljava/io/InterruptedIOException; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.184:Ljava/lang/Long; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.165:Ljava/lang/Long; 35
+Landroid/text/style/ForegroundColorSpan; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.176:Ljava/lang/Long; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.173:Ljava/lang/Long; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.181:Ljava/lang/Byte; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.157:Ljava/lang/Byte; 35
+Landroid/content/res/AssetManager$AssetInputStream; 35
+Landroid/graphics/drawable/TransitionDrawable; 36
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.1:Ljava/lang/Boolean; 37
+Landroid/view/ViewOverlay$OverlayViewGroup; 38
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.11:Ljava/lang/Boolean; 39
+Ljava/util/Observer; 40
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.129:Ljava/lang/Byte; 41
+[Ljava/lang/Byte; 41
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.144:Ljava/lang/Byte; 41
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.164:Ljava/lang/Byte; 42
+Landroid/view/OrientationEventListener; 43
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.195:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.233:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.229:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.128:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.242:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.196:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.208:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.212:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.228:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.205:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.197:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.204:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.207:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.223:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.244:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.174:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.194:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.225:Ljava/lang/Byte; 45
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.239:Ljava/lang/Byte; 45
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.238:Ljava/lang/Byte; 45
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.227:Ljava/lang/Byte; 45
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.152:Ljava/lang/Byte; 46
+Landroid/app/RemoteAction; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.168:Ljava/lang/Byte; 46
+Landroid/text/style/QuoteSpan; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.54:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.124:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.142:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.190:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.114:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.69:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.30:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.133:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.49:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.58:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.143:Ljava/lang/Byte; 47
+Landroid/icu/text/RelativeDateTimeFormatter$AbsoluteUnit; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.82:Ljava/lang/Byte; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.140:Ljava/lang/Byte; 47
+Landroid/icu/text/RelativeDateTimeFormatter;.fallbackCache:[Landroid/icu/text/RelativeDateTimeFormatter$Style; 47
+Landroid/icu/text/RelativeDateTimeFormatter$Style; 47
+Landroid/icu/text/RelativeDateTimeFormatter;.cache:Landroid/icu/text/RelativeDateTimeFormatter$Cache;.cache:Landroid/icu/impl/CacheBase;.map:Ljava/util/concurrent/ConcurrentHashMap; 47
+Landroid/icu/text/RelativeDateTimeFormatter$RelativeUnit; 47
+Landroid/icu/text/RelativeDateTimeFormatter$Direction; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.130:Ljava/lang/Byte; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.43:Ljava/lang/Byte; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.146:Ljava/lang/Byte; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.138:Ljava/lang/Byte; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.136:Ljava/lang/Byte; 48
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.0:Ljava/lang/Byte; 49
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.160:Ljava/lang/Byte; 49
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.169:Ljava/lang/Byte; 50
+Landroid/widget/Spinner; 50
+Landroid/widget/MultiAutoCompleteTextView; 50
+Ljava/util/ArrayList; 50
+Landroid/widget/CheckBox; 50
+Ljava/io/Serializable; 50
+Landroid/widget/RatingBar; 50
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.132:Ljava/lang/Byte; 50
+Landroid/widget/AutoCompleteTextView; 50
+Ljava/util/concurrent/ConcurrentLinkedDeque$Node; 50
+[Ljava/lang/Object; 50
+Landroid/widget/SeekBar; 51
+Ljava/lang/Void; 52
+Landroid/app/ActivityTaskManager;.sInstance:Landroid/util/Singleton; 53
+Landroid/view/ViewRootImpl$$ExternalSyntheticLambda11; 54
+Landroid/view/ViewTreeObserver$OnWindowFocusChangeListener; 55
+Landroid/view/InsetsAnimationThread; 56
+Lcom/android/internal/jank/InteractionJankMonitor$InstanceHolder; 57
+Lcom/android/internal/jank/InteractionJankMonitor; 57
+Landroid/hardware/camera2/CameraCharacteristics;.FLASH_INFO_AVAILABLE:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 58
+Landroid/hardware/display/NightDisplayListener$Callback; 59
+Landroid/media/MediaRouter2Manager; 59
+Landroid/os/HandlerExecutor; 59
+Landroid/os/strictmode/LeakedClosableViolation; 60
+Lcom/android/internal/logging/MetricsLogger; 60
+Lcom/android/internal/os/PowerProfile;.sPowerItemMap:Ljava/util/HashMap; 61
+Lcom/android/internal/os/PowerProfile;.sPowerArrayMap:Ljava/util/HashMap; 61
+Lcom/android/internal/os/PowerProfile;.sModemPowerProfile:Lcom/android/internal/power/ModemPowerProfile;.mPowerConstants:Landroid/util/SparseDoubleArray;.mValues:Landroid/util/SparseLongArray; 61
+Landroid/content/IntentFilter; 62
+Landroid/telecom/TelecomManager; 63
+Ljava/lang/IllegalArgumentException; 64
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.1:Ljava/util/WeakHashMap$Entry;.referent:Ljava/lang/Object; 65
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.1:Ljava/util/WeakHashMap$Entry;.referent:Ljava/lang/Object;.mCache:Ljava/util/LinkedHashMap; 65
+Landroid/telephony/VisualVoicemailSmsFilterSettings;.DEFAULT_ORIGINATING_NUMBERS:Ljava/util/List; 66
+Ljava/util/AbstractList; 68
+Ljava/util/AbstractCollection; 68
+Ljava/util/Collections$EmptyList; 69
+Ljava/lang/StackTraceElement; 69
+[Ljava/lang/StackTraceElement; 69
+Landroid/os/strictmode/Violation; 70
+Ljava/util/List; 71
+Ljava/lang/String; 72
+Ljava/io/ObjectInputStream; 73
+Ljava/io/ObjectStreamClass$Caches;.localDescs:Ljava/util/concurrent/ConcurrentMap; 73
+Ljava/io/ObjectStreamClass$Caches;.reflectors:Ljava/util/concurrent/ConcurrentMap; 73
+Ljava/io/ObjectOutputStream; 73
+Ljava/lang/Number; 74
+Ljava/math/BigInteger; 75
+[B 76
+Landroid/os/Handler; 77
+Landroid/view/accessibility/AccessibilityManager; 78
+Landroid/view/ViewConfiguration;.sConfigurations:Landroid/util/SparseArray;.mKeys:[I 79
+Landroid/view/ViewConfiguration;.sConfigurations:Landroid/util/SparseArray;.mValues:[Ljava/lang/Object; 79
+Landroid/view/ViewConfiguration;.sConfigurations:Landroid/util/SparseArray; 79
+Landroid/widget/FrameLayout; 80
+Lcom/android/internal/inputmethod/ImeTracing; 80
+Lcom/android/internal/policy/DecorView; 80
+Landroid/view/accessibility/AccessibilityNodeIdManager; 80
+Landroid/view/ViewTreeObserver; 80
+Landroid/view/ViewRootImpl; 80
+Landroid/os/SystemProperties;.sChangeCallbacks:Ljava/util/ArrayList; 80
+Landroid/transition/ChangeTransform; 80
+Landroid/window/SurfaceSyncGroup; 80
+Landroid/transition/ChangeClipBounds; 80
+Landroid/view/SurfaceControlRegistry; 80
+Landroid/transition/ChangeImageTransform; 80
+Landroid/widget/LinearLayout; 80
+Landroid/view/ViewStub; 81
+Landroid/text/TextLine;.sCached:[Landroid/text/TextLine; 82
+Landroid/text/TextUtils; 82
+Landroid/graphics/TemporaryBuffer; 82
+Landroid/content/res/ColorStateList;.sCache:Landroid/util/SparseArray; 83
+Landroid/text/Layout;.sTempRect:Landroid/graphics/Rect; 84
+Landroid/widget/ImageView; 85
+Landroid/graphics/drawable/ColorDrawable; 86
+Landroid/os/StrictMode$InstanceTracker;.sInstanceCounts:Ljava/util/HashMap; 87
+Landroid/app/ActivityClient;.INTERFACE_SINGLETON:Landroid/app/ActivityClient$ActivityClientControllerSingleton; 88
+Landroid/app/ActivityClient;.sInstance:Landroid/util/Singleton; 88
+Landroid/view/AbsSavedState$1; 89
+Landroid/app/FragmentManagerState; 90
+Landroid/window/OnBackAnimationCallback; 91
+Landroid/animation/AnimatorInflater;.sTmpTypedValue:Landroid/util/TypedValue; 92
+Landroid/graphics/drawable/RippleDrawable; 93
+Landroid/view/inputmethod/IInputMethodManagerGlobalInvoker; 94
+Landroid/app/ActivityTaskManager;.IActivityTaskManagerSingleton:Landroid/util/Singleton; 95
+Landroid/view/Choreographer; 96
+Lcom/android/internal/os/SomeArgs; 97
+Landroid/graphics/Bitmap; 98
+Landroid/view/autofill/AutofillId; 99
+Landroid/view/inputmethod/BaseInputConnection;.COMPOSING:Ljava/lang/Object; 100
+Landroid/text/Selection;.SELECTION_MEMORY:Ljava/lang/Object; 101
+Landroid/text/Selection;.SELECTION_END:Ljava/lang/Object; 101
+Landroid/text/Selection;.SELECTION_START:Ljava/lang/Object; 101
+Landroid/text/SpannableStringBuilder;.sCachedIntBuffer:[[I 102
+Landroid/text/Selection$MemoryTextWatcher; 103
+Landroid/text/SpanWatcher; 104
+Lcom/android/internal/util/ArrayUtils;.sCache:[Ljava/lang/Object; 105
+Ljava/lang/Integer;.SMALL_NEG_VALUES:[Ljava/lang/String; 106
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 107
+Lsun/nio/ch/SharedFileLockTable;.lockMap:Ljava/util/concurrent/ConcurrentHashMap; 108
+Lsun/nio/ch/FileChannelImpl; 108
+Landroid/database/sqlite/SQLiteDatabase$CursorFactory; 109
+Landroid/database/sqlite/SQLiteDebug$NoPreloadHolder; 110
+Landroid/database/sqlite/SQLiteCompatibilityWalFlags; 110
+Landroid/database/sqlite/SQLiteGlobal; 110
+Landroid/database/CursorWindow; 111
+Landroid/content/ContentResolver; 112
+Ljava/nio/charset/Charset; 113
+Landroid/app/ContextImpl; 114
+Ljava/util/concurrent/Executors$DefaultThreadFactory;.poolNumber:Ljava/util/concurrent/atomic/AtomicInteger; 115
+Landroid/content/pm/PackageManager;.sPackageInfoCache:Landroid/app/PropertyInvalidatedCache;.mCache:Ljava/util/LinkedHashMap; 116
+Landroid/content/pm/PackageManager;.sApplicationInfoCache:Landroid/app/PropertyInvalidatedCache;.mCache:Ljava/util/LinkedHashMap; 117
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager;.systemContext:Ljava/util/logging/LogManager$LoggerContext;.namedLoggers:Ljava/util/Hashtable;.table:[Ljava/util/Hashtable$HashtableEntry; 118
+Landroid/ddm/DdmHandleAppName; 118
+Landroid/provider/DeviceConfigInitializer; 118
+Lsun/misc/Cleaner; 118
+Ldalvik/system/CloseGuard; 118
+Landroid/graphics/Typeface; 118
+Landroid/os/BinderProxy;.sProxyMap:Landroid/os/BinderProxy$ProxyMap;.mMainIndexKeys:[[Ljava/lang/Long; 118
+Landroid/permission/PermissionManager; 118
+Landroid/media/MediaFrameworkPlatformInitializer; 118
+Ljava/util/TimeZone; 118
+Landroid/os/Environment; 118
+Landroid/compat/Compatibility; 118
+Landroid/os/ServiceManager; 118
+Landroid/content/pm/PackageManager;.sApplicationInfoCache:Landroid/app/PropertyInvalidatedCache; 118
+Ljava/util/Locale$NoImagePreloadHolder; 118
+Ljava/lang/System; 118
+Lcom/android/internal/os/RuntimeInit; 118
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager;.systemContext:Ljava/util/logging/LogManager$LoggerContext;.namedLoggers:Ljava/util/Hashtable; 118
+Ldalvik/system/VMRuntime;.THE_ONE:Ldalvik/system/VMRuntime; 118
+Landroid/view/View; 118
+Landroid/hardware/display/DisplayManagerGlobal; 118
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager; 118
+Landroid/telephony/TelephonyFrameworkInitializer; 118
+Landroid/se/omapi/SeFrameworkInitializer; 118
+Landroid/app/LoadedApk;.sApplications:Landroid/util/ArrayMap;.mHashes:[I 118
+Landroid/security/net/config/SystemCertificateSource$NoPreloadHolder; 118
+Landroid/security/net/config/ApplicationConfig; 118
+Landroid/content/res/Resources;.sResourcesHistory:Ljava/util/Set;.c:Ljava/util/Collection;.m:Ljava/util/Map; 118
+Ljava/util/Locale; 118
+Landroid/content/res/Resources;.sResourcesHistory:Ljava/util/Set;.c:Ljava/util/Collection;.m:Ljava/util/Map;.table:[Ljava/util/WeakHashMap$Entry; 118
+Ljava/security/Provider; 118
+Ldalvik/system/ZygoteHooks; 118
+Landroid/os/Message; 118
+Landroid/app/LoadedApk;.sApplications:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object; 118
+Landroid/app/LoadedApk;.sApplications:Landroid/util/ArrayMap; 118
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap; 118
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager;.userContext:Ljava/util/logging/LogManager$LoggerContext;.namedLoggers:Ljava/util/Hashtable; 118
+Ljava/lang/ThreadGroup;.mainThreadGroup:Ljava/lang/ThreadGroup; 118
+Ldalvik/system/RuntimeHooks; 118
+Landroid/nfc/NfcFrameworkInitializer; 118
+Landroid/os/Looper; 118
+Landroid/os/LocaleList; 118
+Ldalvik/system/SocketTagger; 118
+Landroid/icu/util/TimeZone; 118
+Landroid/util/ArraySet; 118
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager;.systemContext:Ljava/util/logging/LogManager$LoggerContext;.root:Ljava/util/logging/LogManager$LogNode; 118
+Landroid/os/BinderProxy;.sProxyMap:Landroid/os/BinderProxy$ProxyMap;.mMainIndexValues:[Ljava/util/ArrayList; 118
+Ljava/util/Random;.seedUniquifier:Ljava/util/concurrent/atomic/AtomicLong; 118
+Landroid/app/ActivityThread; 118
+Landroid/os/Binder; 118
+Ljava/lang/ThreadLocal;.nextHashCode:Ljava/util/concurrent/atomic/AtomicInteger; 119
+Landroid/os/Parcel; 120
+Landroid/system/UnixSocketAddress; 120
+Ljava/lang/ThreadGroup;.systemThreadGroup:Ljava/lang/ThreadGroup; 120
+Ljava/lang/Daemons$FinalizerDaemon;.INSTANCE:Ljava/lang/Daemons$FinalizerDaemon; 120
+Landroid/os/Parcel;.sPairedCreators:Ljava/util/HashMap; 120
+Ljava/lang/Thread; 120
+Landroid/os/Parcel;.mCreators:Ljava/util/HashMap; 120
+Ljava/lang/Daemons$FinalizerDaemon;.INSTANCE:Ljava/lang/Daemons$FinalizerDaemon;.progressCounter:Ljava/util/concurrent/atomic/AtomicInteger; 120
+Landroid/system/StructPollfd; 120
+Ljava/lang/Daemons$HeapTaskDaemon;.INSTANCE:Ljava/lang/Daemons$HeapTaskDaemon; 120
+Landroid/system/StructTimeval; 120
+Ldalvik/system/VMRuntime;.THE_ONE:Ldalvik/system/VMRuntime;.allocationCount:Ljava/util/concurrent/atomic/AtomicInteger; 120
+Ljava/lang/Daemons$ReferenceQueueDaemon;.INSTANCE:Ljava/lang/Daemons$ReferenceQueueDaemon;.progressCounter:Ljava/util/concurrent/atomic/AtomicInteger; 120
+Landroid/os/GraphicsEnvironment;.sInstance:Landroid/os/GraphicsEnvironment; 120
+Ljava/lang/Daemons$FinalizerWatchdogDaemon;.INSTANCE:Ljava/lang/Daemons$FinalizerWatchdogDaemon; 120
+Ljava/lang/ref/FinalizerReference; 120
+Landroid/os/Process; 120
+Ljava/lang/Daemons$ReferenceQueueDaemon;.INSTANCE:Ljava/lang/Daemons$ReferenceQueueDaemon; 120
+Lcom/android/internal/os/BinderInternal; 120
+Landroid/app/ApplicationLoaders;.gApplicationLoaders:Landroid/app/ApplicationLoaders;.mLoaders:Landroid/util/ArrayMap; 121
+Landroid/app/DexLoadReporter;.INSTANCE:Landroid/app/DexLoadReporter;.mDataDirs:Ljava/util/Set;.map:Ljava/util/HashMap; 122
+Ldalvik/system/BaseDexClassLoader; 122
+Landroid/renderscript/RenderScriptCacheDir; 122
+Landroid/graphics/Compatibility; 123
+Llibcore/io/Libcore; 123
+Landroid/provider/FontsContract; 123
+Ljava/security/Security;.version:Ljava/util/concurrent/atomic/AtomicInteger; 123
+Llibcore/net/NetworkSecurityPolicy; 123
+Lsun/security/jca/Providers; 123
+Landroid/graphics/Canvas; 123
+Landroid/os/StrictMode; 124
+Landroid/content/pm/PackageManager;.sPackageInfoCache:Landroid/app/PropertyInvalidatedCache; 125
+Lcom/android/internal/os/StatsdHiddenApiUsageLogger;.sInstance:Lcom/android/internal/os/StatsdHiddenApiUsageLogger; 126
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager;.loggerRefQueue:Ljava/lang/ref/ReferenceQueue; 127
+Landroid/view/WindowManagerGlobal; 128
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;.sPool:Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool; 129
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;.sPool:Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool;.mPool:[Ljava/lang/Object; 129
+Landroid/view/inputmethod/InputMethodManager; 130
+Landroid/media/MediaRouter; 131
+Landroid/hardware/SensorPrivacyManager; 132
+Landroid/os/storage/StorageManager; 133
+Landroid/view/contentcapture/ContentCaptureManager; 134
+Landroid/hardware/input/InputManager; 134
+Landroid/app/people/PeopleManager; 134
+Landroid/media/session/MediaSessionManager; 134
+Landroid/security/attestationverification/AttestationVerificationManager; 134
+Landroid/net/vcn/VcnManager; 134
+Landroid/os/RecoverySystem; 134
+Landroid/net/NetworkPolicyManager; 134
+Landroid/net/wifi/sharedconnectivity/app/SharedConnectivityManager; 134
+Landroid/permission/PermissionControllerManager; 134
+Landroid/app/tare/EconomyManager; 134
+Landroid/view/translation/TranslationManager; 134
+Landroid/view/textclassifier/TextClassificationManager; 134
+Landroid/view/autofill/AutofillManager; 134
+Landroid/os/SystemConfigManager; 134
+Landroid/view/LayoutInflater; 134
+Landroid/credentials/CredentialManager; 134
+Landroid/service/persistentdata/PersistentDataBlockManager; 134
+Landroid/view/textservice/TextServicesManager; 134
+Landroid/app/admin/DevicePolicyManager; 134
+Ljava/lang/StackStreamFactory; 134
+Landroid/view/WindowManager; 134
+Landroid/app/contentsuggestions/ContentSuggestionsManager; 134
+Landroid/media/tv/tunerresourcemanager/TunerResourceManager; 134
+Landroid/telephony/SubscriptionManager; 134
+Landroid/os/HardwarePropertiesManager; 134
+Landroid/media/AudioManager; 135
+Landroid/telephony/TelephonyManager; 136
+Landroid/util/ArrayMap; 137
+Landroid/app/QueuedWork; 138
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.0:Ljava/util/WeakHashMap$Entry; 139
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap; 140
+Ljava/util/concurrent/ScheduledThreadPoolExecutor;.sequencer:Ljava/util/concurrent/atomic/AtomicLong; 141
+Landroid/util/Log; 142
+Ljava/util/Collections$SynchronizedCollection; 143
+Ljava/util/Set; 143
+Ljava/util/Collections$SynchronizedSet; 143
+Ljava/util/Collection; 143
+Ljava/lang/Integer;.SMALL_NONNEG_VALUES:[Ljava/lang/String; 144
+Landroid/content/ComponentName; 145
+Landroid/view/textclassifier/TextLanguage;.EMPTY:Landroid/view/textclassifier/TextLanguage;.mBundle:Landroid/os/Bundle; 146
+Landroid/os/PersistableBundle;.EMPTY:Landroid/os/PersistableBundle; 147
+Landroid/icu/impl/locale/BaseLocale;.CACHE:Landroid/icu/impl/locale/BaseLocale$Cache;._map:Ljava/util/concurrent/ConcurrentHashMap; 148
+Ljava/util/GregorianCalendar; 149
+Ljava/text/DontCareFieldPosition;.INSTANCE:Ljava/text/FieldPosition; 150
+Landroid/app/UiModeManager; 151
+Ljdk/internal/access/SharedSecrets; 152
+Landroid/icu/impl/ZoneMeta;.CANONICAL_ID_CACHE:Landroid/icu/impl/ICUCache; 153
+Landroid/icu/impl/ZoneMeta;.SYSTEM_ZONE_CACHE:Landroid/icu/impl/ZoneMeta$SystemTimeZoneCache;.map:Ljava/util/concurrent/ConcurrentHashMap; 154
+Ljava/time/ZoneOffset;.ID_CACHE:Ljava/util/concurrent/ConcurrentMap; 155
+Ljava/time/ZoneOffset;.ID_CACHE:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node; 155
+Ljava/time/ZoneOffset;.SECONDS_CACHE:Ljava/util/concurrent/ConcurrentMap; 155
+Ljava/time/ZoneOffset;.SECONDS_CACHE:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.0:Ljava/util/concurrent/ConcurrentHashMap$Node;.next:Ljava/util/concurrent/ConcurrentHashMap$Node; 155
+Ljava/time/ZoneOffset;.SECONDS_CACHE:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node; 155
+Landroid/widget/TextView; 156
+Landroid/view/ViewGroup$ChildListForAutoFillOrContentCapture;.sPool:Landroid/util/Pools$SimplePool;.mPool:[Ljava/lang/Object; 157
+Landroid/view/ViewGroup$ChildListForAutoFillOrContentCapture;.sPool:Landroid/util/Pools$SimplePool; 157
+Landroid/view/ViewGroup; 158
+Landroid/graphics/Rect; 159
+Landroid/view/View$BaseSavedState; 160
+Landroid/widget/Button; 161
+Landroid/widget/ImageButton; 162
+Landroid/view/View$OnHoverListener; 163
+Landroid/widget/Toolbar; 164
+Landroid/hardware/display/ColorDisplayManager$ColorDisplayManagerInternal; 165
+Landroid/app/WallpaperManager; 166
+Landroid/graphics/ColorSpace$Model;.RGB:Landroid/graphics/ColorSpace$Model; 166
+Landroid/graphics/drawable/AdaptiveIconDrawable; 167
+Landroid/animation/ValueAnimator$DurationScaleChangeListener; 168
+Landroid/widget/Toast; 168
+Landroid/app/smartspace/SmartspaceSession$OnTargetsAvailableListener; 168
+Landroid/view/CrossWindowBlurListeners; 168
+Landroid/app/servertransaction/ActivityRelaunchItem; 169
+[Ljava/util/concurrent/ForkJoinTask; 169
+Landroid/view/WindowManager$LayoutParams; 169
+Ljava/util/concurrent/ForkJoinPool$WorkQueue; 169
+Landroid/app/prediction/AppTargetEvent; 169
+Lorg/xmlpull/v1/XmlPullParserException; 169
+Landroid/app/servertransaction/ObjectPool;.sPoolMap:Ljava/util/Map; 170
+Landroid/app/servertransaction/ClientTransaction; 170
+Landroid/app/servertransaction/StopActivityItem; 170
+Landroid/system/ErrnoException; 171
+Landroid/hardware/location/ContextHubTransaction$OnCompleteListener; 172
+Landroid/app/PendingIntent$OnFinished; 172
+Ljava/lang/NullPointerException; 173
+Landroid/os/strictmode/DiskReadViolation; 174
+Lorg/apache/http/params/HttpParams; 175
+Landroid/nfc/cardemulation/CardEmulation; 176
+Ljava/io/FileDescriptor; 177
+Landroid/content/pm/PackageManager$OnPermissionsChangedListener; 178
+Landroid/security/keystore2/KeyStoreCryptoOperationUtils; 179
+Landroid/app/ActivityTaskManager; 180
+Landroid/util/EventLog; 181
+Ljava/net/URLConnection; 181
+Ljava/net/SocketException; 181
+Ljava/lang/reflect/InvocationTargetException; 181
+Ljava/lang/Enum; 182
+Landroid/widget/AbsListView$SelectionBoundsAdjuster; 183
+Ljava/lang/ClassNotFoundException; 183
+Landroid/content/SyncStatusObserver; 184
+Landroid/content/AsyncTaskLoader$LoadTask; 185
+Landroid/app/LoaderManager$LoaderCallbacks; 185
+Landroid/webkit/CookieSyncManager; 186
+Landroid/webkit/WebViewProvider$ViewDelegate; 187
+Landroid/webkit/WebView; 187
+Landroid/webkit/WebViewProvider$ScrollDelegate; 187
+Landroid/webkit/WebViewProvider; 187
+Landroid/webkit/WebViewFactory;.sTimestamps:Landroid/webkit/WebViewFactory$StartupTimestamps; 188
+Landroid/webkit/WebViewFactoryProvider; 189
+Landroid/webkit/WebViewFactory; 190
+Landroid/os/PowerManager$OnThermalStatusChangedListener; 191
+Landroid/os/Bundle; 192
+Landroid/widget/ProgressBar; 193
+Landroid/graphics/Bitmap$Config;.ALPHA_8:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/Bitmap$Config;.RGB_565:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/Bitmap$Config;.RGBA_1010102:Landroid/graphics/Bitmap$Config; 194
+Landroid/renderscript/Allocation;.mBitmapOptions:Landroid/graphics/BitmapFactory$Options;.inPreferredConfig:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/Bitmap$Config;.RGBA_F16:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/Bitmap$Config;.ARGB_4444:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/Bitmap$Config;.HARDWARE:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/drawable/StateListDrawable; 195
+Landroid/view/PointerIcon;.gSystemIconsByDisplay:Landroid/util/SparseArray; 196
+Landroid/view/PointerIcon; 196
+Ljavax/net/ssl/SSLServerSocketFactory; 197
+Ljavax/net/ssl/SSLSocketFactory; 198
+Ljavax/net/ssl/HttpsURLConnection$NoPreloadHolder; 198
+Ljavax/net/ssl/SSLSessionContext; 199
+Lcom/android/org/bouncycastle/crypto/CryptoServicesRegistrar; 200
+Lsun/security/x509/PKIXExtensions;.KeyUsage_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/x509/PKIXExtensions;.PolicyConstraints_Id:Lsun/security/util/ObjectIdentifier; 201
+Ljava/security/cert/PKIXRevocationChecker$Option;.ONLY_END_ENTITY:Ljava/security/cert/PKIXRevocationChecker$Option; 201
+Lsun/security/x509/PKIXExtensions;.ExtendedKeyUsage_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/provider/X509Factory;.certCache:Lsun/security/util/Cache; 201
+Lsun/security/x509/PKIXExtensions;.CertificatePolicies_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/x509/PKIXExtensions;.NameConstraints_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/x509/PKIXExtensions;.AuthorityKey_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/provider/X509Factory;.certCache:Lsun/security/util/Cache;.cacheMap:Ljava/util/Map; 201
+Ljava/security/cert/PKIXRevocationChecker$Option;.NO_FALLBACK:Ljava/security/cert/PKIXRevocationChecker$Option; 201
+Lsun/security/x509/PKIXExtensions;.SubjectAlternativeName_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/x509/PKIXExtensions;.PolicyMappings_Id:Lsun/security/util/ObjectIdentifier; 202
+Lsun/security/x509/PKIXExtensions;.InhibitAnyPolicy_Id:Lsun/security/util/ObjectIdentifier; 202
+Lsun/security/x509/PKIXExtensions;.BasicConstraints_Id:Lsun/security/util/ObjectIdentifier; 202
+Ljava/security/Security;.spiMap:Ljava/util/Map; 203
+Lsun/security/x509/X500Name;.commonName_oid:Lsun/security/util/ObjectIdentifier; 204
+Lsun/security/x509/X500Name;.countryName_oid:Lsun/security/util/ObjectIdentifier; 204
+Lsun/security/x509/X500Name;.orgName_oid:Lsun/security/util/ObjectIdentifier; 204
+Ljava/nio/charset/Charset;.cache2:Ljava/util/HashMap; 205
+Ljava/net/URL;.handlers:Ljava/util/Hashtable;.table:[Ljava/util/Hashtable$HashtableEntry; 206
+Ljava/net/URL;.handlers:Ljava/util/Hashtable; 206
+Ljava/net/Inet6AddressImpl;.addressCache:Ljava/net/AddressCache;.cache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap; 207
+Ljava/net/Proxy$Type;.DIRECT:Ljava/net/Proxy$Type; 208
+Ljava/net/ProxySelector;.theProxySelector:Ljava/net/ProxySelector; 208
+Lcom/android/okhttp/okio/SegmentPool; 209
+Lcom/android/okhttp/internal/http/AuthenticatorAdapter;.INSTANCE:Lcom/android/okhttp/Authenticator; 209
+Lcom/android/okhttp/HttpsHandler;.HTTP_1_1_ONLY:Ljava/util/List;.element:Ljava/lang/Object; 209
+Lcom/android/okhttp/ConfigAwareConnectionPool;.instance:Lcom/android/okhttp/ConfigAwareConnectionPool;.networkEventDispatcher:Llibcore/net/event/NetworkEventDispatcher;.listeners:Ljava/util/List; 210
+Lcom/android/okhttp/Dns;.SYSTEM:Lcom/android/okhttp/Dns; 210
+Lcom/android/okhttp/ConfigAwareConnectionPool;.instance:Lcom/android/okhttp/ConfigAwareConnectionPool; 210
+Lcom/android/okhttp/okio/AsyncTimeout; 211
+Ljava/lang/IllegalAccessException; 212
+Ljavax/net/ssl/SSLContext; 213
+Ljavax/net/ssl/HttpsURLConnection; 213
+Ljava/security/Security;.props:Ljava/util/Properties;.map:Ljava/util/concurrent/ConcurrentHashMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.12:Ljava/util/concurrent/ConcurrentHashMap$Node;.next:Ljava/util/concurrent/ConcurrentHashMap$Node; 214
+Ljava/security/Security;.props:Ljava/util/Properties;.map:Ljava/util/concurrent/ConcurrentHashMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.30:Ljava/util/concurrent/ConcurrentHashMap$Node; 214
+Landroid/database/sqlite/SQLiteTransactionListener; 215
+Landroid/accounts/OnAccountsUpdateListener; 216
+Landroid/accounts/AccountManager$20; 217
+Lsun/nio/ch/FileChannelImpl$Unmapper; 218
+Landroid/content/res/Resources;.sResourcesHistory:Ljava/util/Set;.c:Ljava/util/Collection;.m:Ljava/util/Map;.queue:Ljava/lang/ref/ReferenceQueue; 219
+Landroid/text/method/SingleLineTransformationMethod; 220
+Landroid/widget/RelativeLayout; 221
+Landroid/graphics/drawable/BitmapDrawable; 222
+Landroid/graphics/drawable/GradientDrawable; 223
+Landroid/animation/PropertyValuesHolder;.sGetterPropertyMap:Ljava/util/HashMap; 224
+Landroid/animation/PropertyValuesHolder$FloatPropertyValuesHolder;.sJNISetterPropertyMap:Ljava/util/HashMap; 225
+Landroid/graphics/drawable/Drawable;.DEFAULT_TINT_MODE:Landroid/graphics/PorterDuff$Mode; 226
+Landroid/text/StaticLayout$Builder;.sPool:Landroid/util/Pools$SynchronizedPool; 227
+Landroid/text/StaticLayout$Builder;.sPool:Landroid/util/Pools$SynchronizedPool;.mPool:[Ljava/lang/Object; 227
+Ljava/util/concurrent/ThreadLocalRandom; 228
+Landroid/widget/Space; 229
+Landroid/widget/ScrollView; 230
+Landroid/text/style/LineHeightSpan; 231
+Landroid/text/style/TabStopSpan; 232
+Landroid/text/style/ReplacementSpan; 233
+Landroid/text/style/MetricAffectingSpan; 233
+Landroid/text/style/LeadingMarginSpan; 233
+Landroid/text/style/LineBackgroundSpan; 234
+Landroid/text/style/CharacterStyle; 235
+Landroid/text/style/SuggestionSpan; 236
+Landroid/widget/TextView$ChangeWatcher; 237
+Landroid/text/DynamicLayout$Builder;.sPool:Landroid/util/Pools$SynchronizedPool;.mPool:[Ljava/lang/Object; 238
+Landroid/text/DynamicLayout; 238
+Landroid/text/DynamicLayout$ChangeWatcher; 238
+Landroid/text/style/WrapTogetherSpan; 238
+Landroid/text/DynamicLayout$Builder;.sPool:Landroid/util/Pools$SynchronizedPool; 238
+Landroid/text/method/LinkMovementMethod; 239
+Landroid/text/style/ClickableSpan; 240
+Ljava/util/logging/LogRecord;.globalSequenceNumber:Ljava/util/concurrent/atomic/AtomicLong; 241
+Ljava/lang/Runtime;.currentRuntime:Ljava/lang/Runtime; 242
+Landroid/content/pm/LauncherActivityInfo; 243
+Landroid/database/sqlite/SQLiteMisuseException; 243
+Landroid/speech/tts/TextToSpeech$Connection$SetupConnectionAsyncTask; 243
+Landroid/database/sqlite/SQLiteCantOpenDatabaseException; 243
+Landroid/database/sqlite/SQLiteDatabaseCorruptException; 243
+Landroid/database/sqlite/SQLiteDatabaseLockedException; 243
+Ljava/util/Map$Entry; 243
+Ljava/util/zip/ZipException; 243
+Landroid/database/sqlite/SQLiteAccessPermException; 243
+Landroid/speech/tts/TextToSpeech$OnInitListener; 243
+Landroid/app/Notification$MessagingStyle; 244
+Landroid/text/TextUtils$TruncateAt; 245
+Landroid/app/smartspace/SmartspaceTarget; 246
+Landroid/app/prediction/AppTarget; 246
+Landroid/app/smartspace/uitemplatedata/BaseTemplateData; 246
+Landroid/location/LocationManager;.sLocationListeners:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry; 247
+Landroid/location/LocationManager;.sLocationListeners:Ljava/util/WeakHashMap; 247
+Landroid/service/notification/ConditionProviderService; 248
+Landroid/os/WorkSource; 249
+Landroid/security/keystore2/AndroidKeyStoreProvider; 249
+Ljava/net/Socket; 249
+Lcom/android/internal/listeners/ListenerTransport; 249
+Landroid/os/ParcelUuid; 250
+Landroid/telephony/emergency/EmergencyNumber; 251
+Lcom/android/internal/telephony/uicc/UiccProfile$4; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$IncomingSms; 251
+Lcom/android/internal/telephony/SmsStorageMonitor$1; 251
+Lcom/android/internal/telephony/TelephonyDevController; 251
+Lcom/android/internal/telephony/uicc/UiccController; 251
+Lcom/android/internal/telephony/emergency/EmergencyNumberTracker$1; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$DataCallSession; 251
+Lcom/android/internal/telephony/TelephonyDevController;.mSims:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$RcsAcsProvisioningStats; 251
+Ljava/lang/UnsupportedOperationException; 251
+Landroid/database/CursorToBulkCursorAdaptor; 251
+Lcom/android/internal/telephony/satellite/PointingAppController; 251
+Landroid/telephony/ModemActivityInfo; 251
+Lcom/android/internal/telephony/imsphone/ImsPhone; 251
+Lcom/android/internal/telephony/ServiceStateTracker; 251
+Lcom/android/internal/telephony/IccSmsInterfaceManager; 251
+Lcom/android/internal/telephony/util/NotificationChannelController$1; 251
+Lcom/android/internal/telephony/RilWakelockInfo; 251
+Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler$GsmCbTestBroadcastReceiver; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipTransportFeatureTagStats; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$UceEventStats; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$BindingState; 251
+Lcom/android/internal/telephony/ims/ImsResolver$3; 251
+Landroid/net/NetworkPolicyManager$SubscriptionCallbackProxy; 251
+Lcom/android/internal/telephony/TelephonyDevController;.mModems:Ljava/util/ArrayList; 251
+Landroid/telephony/ims/aidl/IImsServiceController$Stub$Proxy; 251
+Lcom/android/internal/telephony/CarrierPrivilegesTracker$1; 251
+Lcom/android/internal/telephony/CommandException; 251
+Lcom/android/ims/FeatureConnector$1; 251
+Lcom/android/internal/telephony/IWapPushManager; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipDelegateStats; 251
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mTtyModeReceivedRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Landroid/view/textclassifier/TextLanguage;.EMPTY:Landroid/view/textclassifier/TextLanguage;.mBundle:Landroid/os/Bundle;.mClassLoader:Ljava/lang/ClassLoader; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mMmiCompleteRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/i18n/timezone/TelephonyLookup; 251
+Landroid/telephony/BarringInfo$BarringServiceInfo; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$NetworkRequests; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$ConnectedState$14; 251
+Lcom/android/internal/telephony/SmsBroadcastUndelivered; 251
+Lcom/android/internal/telephony/LocaleTracker; 251
+Lcom/android/internal/telephony/PhoneSubInfoController; 251
+Lcom/android/internal/telephony/CarrierKeyDownloadManager$1; 251
+Lcom/android/internal/telephony/GsmCdmaCallTracker$1; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.339:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/ServiceStateTracker$1; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.353:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/euicc/EuiccCardController$SimSlotStatusChangedBroadcastReceiver; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$PresenceNotifyEvent; 251
+Lcom/android/internal/telephony/SimActivationTracker$1; 251
+Landroid/telephony/ModemInfo; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.1393:[Ljava/lang/String; 251
+Landroid/telephony/CellSignalStrengthWcdma; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteProvision; 251
+Lcom/android/internal/telephony/PhoneConfigurationManager; 251
+Lcom/android/internal/telephony/SmsApplication$SmsPackageMonitor; 251
+Landroid/telephony/TelephonyRegistryManager$3; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$VoiceCallSession; 251
+Landroid/os/Handler$MessengerImpl; 251
+Lcom/android/internal/telephony/LocaleTracker$1; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$CellularDataServiceSwitch; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mInCallVoicePrivacyOffRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteSosMessageRecommender; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationServiceDescStats; 251
+Lcom/android/internal/telephony/uicc/UiccPkcs15$Pkcs15Selector; 251
+Lcom/android/internal/telephony/CarrierResolver$2; 251
+Lcom/android/internal/telephony/CarrierActionAgent$1; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mPhones:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/SmsController; 251
+Lcom/android/internal/telephony/uicc/euicc/EuiccCardException; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationTermination; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.1125:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/NetworkTypeController$1; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.803:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/uicc/asn1/TagNotFoundException; 251
+Lcom/android/internal/telephony/CarrierServiceBindHelper$1; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$CellularServiceState; 251
+Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager; 251
+Lcom/android/internal/telephony/InboundSmsHandler$NewMessageNotificationActionReceiver; 251
+Lcom/android/internal/telephony/CarrierActionAgent; 251
+Lcom/android/i18n/timezone/TimeZoneFinder; 251
+Lcom/android/internal/telephony/RILRequest; 251
+Lcom/android/internal/telephony/RIL;.sRilTimeHistograms:Landroid/util/SparseArray; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.33:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/MccTable; 251
+Lcom/android/internal/telephony/uicc/UiccProfile$2; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$CarrierIdMismatch; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.1235:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules; 251
+Landroid/telephony/CellSignalStrengthTdscdma; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsDedicatedBearerListenerEvent; 251
+Lcom/android/internal/telephony/SmsDispatchersController; 251
+Landroid/timezone/TelephonyLookup; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteOutgoingDatagram; 251
+Lcom/android/internal/telephony/SMSDispatcher$1; 251
+Lcom/android/internal/telephony/AppSmsManager; 251
+Landroid/timezone/TimeZoneFinder; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mBackgroundCalls:Ljava/util/ArrayList; 251
+Lcom/android/ims/rcs/uce/eab/EabProvider; 251
+Lcom/android/internal/telephony/uicc/PinStorage$1; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsDedicatedBearerEvent; 251
+Landroid/telephony/CellSignalStrengthLte; 251
+Landroid/telephony/ims/ProvisioningManager$Callback$CallbackBinder; 251
+Lcom/android/ims/ImsManager;.IMS_STATS_CALLBACKS:Landroid/util/SparseArray;.mKeys:[I 251
+Landroid/telephony/CellSignalStrengthNr; 251
+Lcom/android/internal/telephony/SomeArgs; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mInCallVoicePrivacyOnRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/StateMachine$SmHandler; 251
+Lcom/android/internal/telephony/PackageChangeReceiver; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$OutgoingShortCodeSms; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$NetworkRequestsV2; 251
+Lcom/android/internal/telephony/nano/TelephonyProto$RilDataCall; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$AvailableState; 251
+Lcom/android/ims/internal/IImsServiceFeatureCallback$Stub$Proxy; 251
+Landroid/telephony/data/ApnSetting;.APN_TYPE_INT_MAP:Ljava/util/Map; 251
+Lcom/android/internal/telephony/RadioInterfaceCapabilityController; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationStats; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$VoiceCallRatUsage; 251
+Lcom/android/internal/telephony/metrics/TelephonyMetrics; 251
+Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyCallSession$Event$RilCall; 251
+Lcom/android/internal/telephony/NetworkRegistrationManager$NetworkRegStateCallback; 251
+Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$ConnectedState; 251
+Lcom/android/internal/telephony/RadioConfig; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$DisconnectedState; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteSession; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mDisplayInfoRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/phone/ecc/nano/ProtobufEccData$EccInfo; 251
+Lcom/android/internal/telephony/GsmCdmaPhone; 251
+Lcom/android/internal/telephony/TelephonyTester$1; 251
+Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler$CdmaScpTestBroadcastReceiver; 251
+Lcom/android/internal/telephony/NetworkTypeController$DefaultState; 251
+Landroid/net/TelephonyNetworkSpecifier; 251
+Lcom/android/internal/telephony/NitzStateMachine; 251
+Landroid/app/timezonedetector/TimeZoneDetector; 251
+Lcom/android/internal/telephony/IntentBroadcaster$1; 251
+Lcom/android/internal/telephony/uicc/UiccStateChangedLauncher; 251
+Lcom/android/internal/telephony/ims/ImsResolver$1; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$OutgoingSms; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$UnmeteredNetworks; 251
+Landroid/view/textclassifier/TextLanguage;.EMPTY:Landroid/view/textclassifier/TextLanguage;.mBundle:Landroid/os/Bundle;.mClassLoader:Ljava/lang/ClassLoader;.packages:Ljava/util/Map;.m:Ljava/util/Map; 251
+Lcom/android/internal/telephony/euicc/EuiccController; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mForegroundCalls:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/satellite/SatelliteModemInterface; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.531:[Ljava/lang/String; 251
+Lcom/android/ims/ImsManager;.IMS_STATS_CALLBACKS:Landroid/util/SparseArray; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$1; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.467:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipMessageResponse; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipTransportSession; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$UnavailableState; 251
+Lcom/android/internal/telephony/DeviceStateMonitor$3; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mSignalInfoRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/ims/ImsManager;.IMS_STATS_CALLBACKS:Landroid/util/SparseArray;.mValues:[Ljava/lang/Object; 251
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager; 251
+Lcom/android/internal/telephony/DisplayInfoController; 251
+Lcom/android/internal/telephony/ims/ImsResolver$2; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.1377:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyServiceState$NetworkRegistrationInfo; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteController; 251
+Landroid/telephony/ims/RegistrationManager$RegistrationCallback$RegistrationBinder; 251
+Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$EmergencyNumbersInfo; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$GbaEvent; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.23:[Ljava/lang/String; 251
+Landroid/telephony/CellSignalStrengthCdma; 251
+Landroid/telephony/TelephonyLocalConnection; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteIncomingDatagram; 251
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker$2; 251
+Lcom/android/internal/telephony/ims/ImsResolver; 251
+Lcom/android/internal/telephony/SmsStorageMonitor; 251
+Lcom/android/internal/telephony/uicc/UiccProfile; 251
+Landroid/telephony/ims/ImsMmTelManager$CapabilityCallback$CapabilityBinder; 251
+Lcom/android/internal/telephony/euicc/EuiccCardController; 251
+Lcom/android/internal/telephony/SmsBroadcastUndelivered$1; 251
+Lcom/android/internal/telephony/GsmCdmaCallTracker; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$RcsClientProvisioningStats; 251
+Lcom/android/internal/telephony/cat/CatService; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.761:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/SmsApplication; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mDisconnectRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/PhoneFactory; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mHandlerMap:Ljava/util/HashMap; 251
+Landroid/os/AsyncResult; 251
+Lcom/android/internal/telephony/ProxyController; 251
+Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler$CdmaCbTestBroadcastReceiver; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.453:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/MultiSimSettingController; 251
+Ljava/io/BufferedReader; 251
+Landroid/telephony/CellSignalStrengthGsm; 251
+Lcom/android/internal/telephony/SimActivationTracker; 251
+Lcom/android/internal/telephony/CellBroadcastServiceManager; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mRingingCalls:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/IntentBroadcaster; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationFeatureTagStats; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$EuiccPackageMonitor; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mSuppServiceFailedRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Landroid/view/textclassifier/TextLanguage;.EMPTY:Landroid/view/textclassifier/TextLanguage;.mBundle:Landroid/os/Bundle;.mClassLoader:Ljava/lang/ClassLoader;.packages:Ljava/util/Map;.m:Ljava/util/Map;.table:[Ljava/util/HashMap$Node; 251
+Lcom/android/internal/telephony/CarrierServiceBindHelper$CarrierServicePackageMonitor; 251
+Lcom/android/internal/telephony/TelephonyComponentFactory; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.637:[Ljava/lang/String; 251
+Lcom/android/phone/ecc/nano/ProtobufEccData$CountryInfo; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.651:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/SmsUsageMonitor; 251
+Lcom/android/internal/telephony/CommandException$Error;.INVALID_SIM_STATE:Lcom/android/internal/telephony/CommandException$Error; 251
+Landroid/hardware/display/DisplayManagerGlobal$DisplayManagerCallback; 252
+Landroid/app/ActivityThread$ApplicationThread; 252
+Landroid/app/ActivityManager$MyUidObserver; 253
+Landroid/media/browse/MediaBrowser$ServiceCallbacks; 253
+Landroid/media/session/MediaController$CallbackStub; 253
+Landroid/media/session/MediaSessionManager$OnMediaKeyEventSessionChangedListener; 253
+Landroid/app/PendingIntent$CancelListener; 253
+Landroid/media/AudioManager$2; 253
+Landroid/database/ContentObserver$Transport; 253
+Landroid/media/session/MediaSessionManager$SessionsChangedWrapper$1; 253
+Landroid/content/ContentProvider$PipeDataWriter; 254
+Landroid/security/net/config/UserCertificateSource$NoPreloadHolder; 255
+Landroid/view/Window$Callback; 256
+Landroid/transition/TransitionManager;.sDefaultTransition:Landroid/transition/Transition;.mTransitions:Ljava/util/ArrayList;.elementData:[Ljava/lang/Object;.1:Landroid/transition/ChangeBounds;.mCurrentAnimators:Ljava/util/ArrayList; 256
+Landroid/transition/TransitionManager;.sDefaultTransition:Landroid/transition/Transition;.mTransitions:Ljava/util/ArrayList;.elementData:[Ljava/lang/Object;.2:Landroid/transition/Fade;.mCurrentAnimators:Ljava/util/ArrayList; 256
+Landroid/transition/TransitionManager;.sPendingTransitions:Ljava/util/ArrayList; 256
+Landroid/transition/TransitionManager;.sDefaultTransition:Landroid/transition/Transition;.mTransitions:Ljava/util/ArrayList;.elementData:[Ljava/lang/Object;.0:Landroid/transition/Fade;.mCurrentAnimators:Ljava/util/ArrayList; 256
+Landroid/view/AttachedSurfaceControl$OnBufferTransformHintChangedListener; 257
+Landroid/webkit/ValueCallback; 258
+Landroid/webkit/WebResourceRequest; 258
+Landroid/webkit/WebChromeClient$CustomViewCallback; 258
+Landroid/hardware/camera2/CameraCharacteristics;.INFO_SUPPORTED_HARDWARE_LEVEL:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 258
+Landroid/accounts/Account; 258
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 258
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_AVAILABLE_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/params/StreamConfigurationDuration; 259
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_AVAILABLE_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_AVAILABLE_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.HEIC_AVAILABLE_HEIC_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/params/HighSpeedVideoConfiguration; 259
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+I 259
+Landroid/hardware/camera2/CameraCharacteristics;.REQUEST_AVAILABLE_CAPABILITIES:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/params/StreamConfiguration; 259
+Z 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_PIXEL_ARRAY_SIZE:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.LENS_FOCAL_LENGTH:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.LENS_INFO_AVAILABLE_APERTURES:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.DISTORTION_CORRECTION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.EXTENSION_STRENGTH:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+J 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_PHYSICAL_SIZE:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.TONEMAP_PRESET_CURVE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+B 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AF_TRIGGER:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_EXPOSURE_COMPENSATION:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+[D 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AWB_REGIONS:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.REQUEST_AVAILABLE_SESSION_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_EXPOSURE_TIME:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_CALIBRATION_TRANSFORM2:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.COLOR_CORRECTION_TRANSFORM:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/content/res/Resources$Theme; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_LOCK:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+F 260
+Landroid/hardware/camera2/CaptureRequest;.LENS_FILTER_DENSITY:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.LENS_OPTICAL_STABILIZATION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.NOISE_REDUCTION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_FRAME_DURATION:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_REGIONS:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_EXTENDED_SCENE_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.STATISTICS_OIS_DATA_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_TEST_PATTERN_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.HOT_PIXEL_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_ANTIBANDING_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.STATISTICS_LENS_SHADING_MAP_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SCALER_CROP_REGION:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.LENS_FOCUS_DISTANCE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.TONEMAP_GAMMA:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_REFERENCE_ILLUMINANT2:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_REFERENCE_ILLUMINANT1:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+[F 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_ZOOM_RATIO:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.COLOR_CORRECTION_ABERRATION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.TONEMAP_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.REQUEST_AVAILABLE_REQUEST_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SCALER_ROTATE_AND_CROP:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.COLOR_CORRECTION_GAINS:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_COLOR_TRANSFORM1:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AF_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_SENSITIVITY:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.LENS_INFO_AVAILABLE_FOCAL_LENGTHS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_OPTICAL_BLACK_REGIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.JPEG_QUALITY:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.FLASH_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_POST_RAW_SENSITIVITY_BOOST:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_WHITE_LEVEL:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_SETTINGS_OVERRIDE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+[Landroid/hardware/camera2/params/MeteringRectangle; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AWB_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.LOGICAL_MULTI_CAMERA_PHYSICAL_IDS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_EXPOSURE_TIME_RANGE:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Ljava/lang/Float; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_ENABLE_ZSL:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.INFO_DEVICE_STATE_ORIENTATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_CALIBRATION_TRANSFORM1:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.EDGE_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_CAPTURE_INTENT:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_ORIENTATION:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.JPEG_ORIENTATION:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_COLOR_TRANSFORM2:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+[J 260
+Landroid/hardware/camera2/CameraCharacteristics;.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Ljava/util/concurrent/Phaser; 260
+Landroid/hardware/camera2/CaptureRequest;.BLACK_LEVEL_LOCK:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.COLOR_CORRECTION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_SCENE_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.JPEG_THUMBNAIL_SIZE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SHADING_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.STATISTICS_FACE_DETECT_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.STATISTICS_HOT_PIXEL_MAP_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AUTOFRAMING:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_TARGET_FPS_RANGE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AWB_LOCK:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_TEST_PATTERN_DATA:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_PRECAPTURE_TRIGGER:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.FLASH_STRENGTH_LEVEL:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_VIDEO_STABILIZATION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Ljava/lang/Boolean; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_EFFECT_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.LENS_APERTURE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.JPEG_THUMBNAIL_QUALITY:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AF_REGIONS:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Ljava/lang/Long; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_PIXEL_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+[Ljava/lang/String; 261
+[Z 262
+Ljava/lang/Class$Caches;.genericInterfaces:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap; 263
+Ljava/util/Map; 264
+Ljava/nio/Bits; 265
+Ljava/nio/DirectByteBuffer; 266
+Ljava/io/File; 267
+Ljava/nio/ByteBuffer; 268
+Ljava/io/InputStream; 269
+Landroid/os/ParcelFileDescriptor; 270
+Landroid/os/BinderProxy;.sProxyMap:Landroid/os/BinderProxy$ProxyMap; 271
+Landroid/app/PendingIntent; 272
+Landroid/content/Intent; 273
+Landroid/net/Uri$HierarchicalUri; 274
+Landroid/net/Uri$StringUri; 275
+Landroid/net/Uri$PathPart;.EMPTY:Landroid/net/Uri$PathPart; 276
+Lcom/android/internal/telephony/MccTable;.FALLBACKS:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.6:Ljava/util/HashMap$Node;.key:Ljava/lang/Object; 277
+Landroid/icu/text/DecimalFormatSymbols;.cachedLocaleData:Landroid/icu/impl/CacheBase;.map:Ljava/util/concurrent/ConcurrentHashMap; 278
+Llibcore/icu/DecimalFormatData;.CACHE:Ljava/util/concurrent/ConcurrentHashMap; 279
+Landroid/icu/impl/CurrencyData;.provider:Landroid/icu/impl/CurrencyData$CurrencyDisplayInfoProvider; 280
+Lcom/android/internal/infra/AndroidFuture; 281
+Lcom/android/internal/util/LatencyTracker$Action; 282
+Landroid/app/AppOpsManager$Mode; 283
+Landroid/view/accessibility/AccessibilityManager$AccessibilityServicesStateChangeListener; 284
+Landroid/annotation/IdRes; 285
+Landroid/content/pm/PackageItemInfo; 286
+Ljava/util/Random; 287
+Landroid/widget/RadioButton; 288
+Lcom/android/internal/policy/PhoneWindow$PanelFeatureState$SavedState; 289
+Landroid/graphics/Insets; 290
+Landroid/view/View;.sNextGeneratedId:Ljava/util/concurrent/atomic/AtomicInteger; 291
+Landroid/graphics/drawable/LayerDrawable; 292
+Landroid/animation/LayoutTransition; 293
+Llibcore/reflect/AnnotationFactory;.cache:Ljava/util/Map; 294
+Llibcore/reflect/AnnotationFactory;.cache:Ljava/util/Map;.table:[Ljava/util/WeakHashMap$Entry; 294
+Ljava/lang/reflect/Proxy;.proxyClassCache:Ljava/lang/reflect/WeakCache;.reverseMap:Ljava/util/concurrent/ConcurrentMap; 295
+Ljava/lang/reflect/Proxy$ProxyClassFactory;.nextUniqueNumber:Ljava/util/concurrent/atomic/AtomicLong; 295
+Ljava/lang/reflect/Proxy;.proxyClassCache:Ljava/lang/reflect/WeakCache;.map:Ljava/util/concurrent/ConcurrentMap; 296
+Ljava/lang/Object; 297
+Ljava/lang/invoke/MethodType;.internTable:Ljava/lang/invoke/MethodType$ConcurrentWeakInternSet;.map:Ljava/util/concurrent/ConcurrentMap; 298
+Ljava/nio/channels/SocketChannel;.dexCache:Ljava/lang/Object; 298
+Ljava/lang/invoke/MethodType;.objectOnlyTypes:[Ljava/lang/invoke/MethodType; 299
+Ljava/util/concurrent/ForkJoinTask; 300
+Ljava/util/concurrent/CompletableFuture; 301
+Landroid/app/Notification$BigTextStyle; 302
+Landroid/content/pm/ApplicationInfo; 303
+Ljava/security/Signature;.signatureInfo:Ljava/util/Map;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.13:Ljava/util/concurrent/ConcurrentHashMap$Node;.next:Ljava/util/concurrent/ConcurrentHashMap$Node;.next:Ljava/util/concurrent/ConcurrentHashMap$Node; 304
+Lsun/security/x509/X500Name;.stateName_oid:Lsun/security/util/ObjectIdentifier; 305
+Lsun/security/x509/X500Name;.localityName_oid:Lsun/security/util/ObjectIdentifier; 306
+Lsun/security/x509/X500Name;.orgUnitName_oid:Lsun/security/util/ObjectIdentifier; 306
+Ljava/util/UUID; 307
+Landroid/app/slice/Slice; 308
+Ljava/util/Locale;.FRENCH:Ljava/util/Locale; 308
+Landroid/os/NullVibrator; 308
+Ldalvik/system/CloseGuard;.MESSAGE:Ljava/lang/String; 308
+Lsun/util/locale/BaseLocale$Cache;.CACHE:Lsun/util/locale/BaseLocale$Cache;.map:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.22:Ljava/util/concurrent/ConcurrentHashMap$Node;.val:Ljava/lang/Object;.referent:Ljava/lang/Object; 308
+Ljava/util/Locale$Cache;.LOCALECACHE:Ljava/util/Locale$Cache;.map:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.24:Ljava/util/concurrent/ConcurrentHashMap$Node;.val:Ljava/lang/Object;.referent:Ljava/lang/Object; 308
+Landroid/app/Activity$$ExternalSyntheticLambda0; 308
+Landroid/icu/impl/locale/BaseLocale;.CACHE:Landroid/icu/impl/locale/BaseLocale$Cache;._map:Ljava/util/concurrent/ConcurrentHashMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.0:Ljava/util/concurrent/ConcurrentHashMap$Node; 308
+Ljava/util/Locale;.ITALIAN:Ljava/util/Locale; 308
+Landroid/media/MediaRouter2Manager$Callback; 308
+Lsun/util/locale/BaseLocale$Cache;.CACHE:Lsun/util/locale/BaseLocale$Cache;.map:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.29:Ljava/util/concurrent/ConcurrentHashMap$Node;.val:Ljava/lang/Object;.referent:Ljava/lang/Object; 308
+Ljava/util/Locale;.GERMAN:Ljava/util/Locale; 309
+Landroid/icu/impl/StandardPlural; 310
+Landroid/icu/impl/number/range/StandardPluralRanges; 311
+Landroid/icu/impl/PluralRulesLoader;.loader:Landroid/icu/impl/PluralRulesLoader; 311
+Landroid/icu/impl/PluralRulesLoader;.loader:Landroid/icu/impl/PluralRulesLoader;.pluralRulesCache:Ljava/util/Map; 311
+Landroid/icu/text/PluralRules$Operand; 311
+Landroid/icu/util/Calendar;.PATTERN_CACHE:Landroid/icu/impl/ICUCache; 312
+Landroid/icu/impl/DateNumberFormat;.CACHE:Landroid/icu/impl/SimpleCache; 313
+Landroid/text/format/DateFormat; 314
+Landroid/view/View$OnDragListener; 315
+Landroid/hardware/input/InputManager$InputDeviceListener; 316
+Landroid/hardware/input/InputManagerGlobal; 317
+Landroid/hardware/SystemSensorManager; 318
+Lcom/android/internal/os/BackgroundThread; 319
+Ljava/lang/Throwable; 320
+Landroid/app/NotificationManager; 321
+Landroid/app/NotificationChannel; 322
+Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener; 323
+Landroid/content/pm/VersionedPackage; 324
+Landroid/app/AppOpsManager; 325
+Ldalvik/system/ZipPathValidator; 326
+Landroid/content/pm/PackageManager;.sPackageInfoCache:Landroid/app/PropertyInvalidatedCache;.mSkips:[J 327
+Landroid/content/pm/PackageManager;.sApplicationInfoCache:Landroid/app/PropertyInvalidatedCache;.mSkips:[J 328
+Lsun/util/locale/BaseLocale$Cache;.CACHE:Lsun/util/locale/BaseLocale$Cache;.map:Ljava/util/concurrent/ConcurrentMap; 329
+Landroid/content/Context; 330
+Ljava/util/concurrent/Executor; 331
+Ljava/util/concurrent/ScheduledExecutorService; 332
+Ljava/util/concurrent/ExecutorService; 332
+Landroid/view/Window$OnFrameMetricsAvailableListener; 333
+Ljava/lang/annotation/Annotation; 334
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 335
+Ljava/util/concurrent/CancellationException; 336
+Ljava/lang/NoSuchMethodException; 337
+Landroid/os/strictmode/CustomViolation; 338
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.3:Ljava/util/WeakHashMap$Entry; 339
+Lcom/android/internal/policy/PhoneWindow; 340
+Landroid/view/autofill/AutofillValue; 340
+Landroid/widget/TextView$SavedState; 341
+Landroid/text/method/MetaKeyKeyListener;.SYM:Ljava/lang/Object; 342
+Landroid/text/method/MetaKeyKeyListener;.ALT:Ljava/lang/Object; 342
+Landroid/text/method/MetaKeyKeyListener;.SELECTING:Ljava/lang/Object; 342
+Landroid/text/method/MetaKeyKeyListener;.CAP:Ljava/lang/Object; 342
+Landroid/widget/PopupWindow$PopupBackgroundView; 343
+Landroid/widget/TextView;.TEMP_RECTF:Landroid/graphics/RectF; 343
+Landroid/text/method/ScrollingMovementMethod; 343
+Landroid/icu/impl/locale/UnicodeLocaleExtension;.EMPTY_SORTED_SET:Ljava/util/SortedSet;.m:Ljava/util/NavigableMap; 343
+Landroid/widget/PopupWindow$PopupDecorView; 343
+Landroid/widget/Editor$TextRenderNode; 343
+Landroid/widget/Editor$PositionListener; 344
+Landroid/text/style/SpellCheckSpan; 345
+Landroid/text/method/ArrowKeyMovementMethod; 346
+Landroid/text/method/TextKeyListener;.sInstance:[Landroid/text/method/TextKeyListener; 346
+Landroid/text/TextUtils$TruncateAt;.MARQUEE:Landroid/text/TextUtils$TruncateAt; 347
+Landroid/view/autofill/Helper; 348
+Lcom/android/internal/util/LatencyTracker; 349
+Lcom/android/internal/util/LatencyTracker$SLatencyTrackerHolder; 349
+Landroid/graphics/drawable/Icon; 350
+Landroid/text/style/AlignmentSpan; 351
+Landroid/text/MeasuredParagraph;.sPool:Landroid/util/Pools$SynchronizedPool;.mPool:[Ljava/lang/Object; 352
+Landroid/text/MeasuredParagraph;.sPool:Landroid/util/Pools$SynchronizedPool; 352
+Landroid/icu/impl/ICUResourceBundleReader;.CACHE:Landroid/icu/impl/ICUResourceBundleReader$ReaderCache;.map:Ljava/util/concurrent/ConcurrentHashMap; 353
+Landroid/location/ILocationManager$Stub;.dexCache:Ljava/lang/Object; 354
+Landroid/annotation/CurrentTimeMillisLong; 355
+Ljava/lang/reflect/Method; 356
+Lcom/android/internal/os/ZygoteInit; 356
+Landroid/database/DatabaseUtils; 356
+Landroid/os/HandlerThread; 356
+Ljava/security/Signature;.signatureInfo:Ljava/util/Map;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node; 357
+Ljava/security/Signature;.signatureInfo:Ljava/util/Map; 358
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.queue:Ljava/lang/ref/ReferenceQueue; 359
+Landroid/telephony/TelephonyRegistryManager; 360
+Landroid/graphics/HardwareRenderer; 361
+Landroid/os/BinderProxy; 362
+Landroid/app/compat/CompatChanges;.QUERY_CACHE:Landroid/app/compat/ChangeIdStateCache;.mCache:Ljava/util/LinkedHashMap; 363
+Landroid/app/compat/CompatChanges;.QUERY_CACHE:Landroid/app/compat/ChangeIdStateCache; 363
+Landroid/app/AlarmManager; 364
+Landroid/net/metrics/DhcpClientEvent; 365
+[I 366
+Landroid/media/MediaCodecList; 367
+Landroid/graphics/drawable/InsetDrawable; 368
+Landroid/widget/ProgressBar$SavedState; 369
+Landroid/widget/ScrollView$SavedState; 370
+Landroid/graphics/drawable/AnimatedVectorDrawable; 371
+Landroid/widget/ListView; 372
+Landroid/widget/AbsListView; 373
+Landroid/widget/AbsListView$SavedState; 373
+Landroid/widget/CompoundButton$SavedState; 374
+Landroid/widget/HorizontalScrollView$SavedState; 375
+Landroid/widget/HorizontalScrollView; 376
+Landroid/icu/text/MeasureFormat;.hmsTo012:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.1:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 377
+Landroid/icu/text/MeasureFormat;.hmsTo012:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.6:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 377
+Landroid/view/View$OnSystemUiVisibilityChangeListener; 378
+Ljava/util/AbstractMap; 379
+Landroid/telephony/euicc/EuiccCardManager$ResultCallback; 380
+Ljava/lang/Character$UnicodeBlock;.CJK_SYMBOLS_AND_PUNCTUATION:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.KANBUN:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.HANGUL_COMPATIBILITY_JAMO:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.KATAKANA:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.HANGUL_SYLLABLES:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.ENCLOSED_CJK_LETTERS_AND_MONTHS:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.HANGUL_JAMO:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.BOPOMOFO_EXTENDED:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.CJK_COMPATIBILITY_FORMS:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.BOPOMOFO:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.HIRAGANA:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.HALFWIDTH_AND_FULLWIDTH_FORMS:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.KANGXI_RADICALS:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.CJK_RADICALS_SUPPLEMENT:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.KATAKANA_PHONETIC_EXTENSIONS:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.CJK_COMPATIBILITY:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:Ljava/lang/Character$UnicodeBlock; 382
+Ljava/lang/Character$UnicodeBlock;.CJK_COMPATIBILITY_IDEOGRAPHS:Ljava/lang/Character$UnicodeBlock; 382
+Ljava/lang/Character$UnicodeBlock;.CJK_UNIFIED_IDEOGRAPHS:Ljava/lang/Character$UnicodeBlock; 382
+Ljava/lang/Character$UnicodeBlock;.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A:Ljava/lang/Character$UnicodeBlock; 382
+Ljava/lang/Character$UnicodeBlock;.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B:Ljava/lang/Character$UnicodeBlock; 382
+Lcom/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry; 383
+Landroid/view/Window$DecorCallback; 383
+Landroid/view/inputmethod/EditorInfo; 383
+Landroid/view/MenuItem$OnActionExpandListener; 384
+Ljava/util/Locale;.JAPANESE:Ljava/util/Locale; 385
+Ljava/util/Locale;.KOREAN:Ljava/util/Locale; 385
+Lcom/android/internal/config/appcloning/AppCloningDeviceConfigHelper; 386
+Landroid/telecom/PhoneAccountHandle; 387
+Landroid/content/AsyncQueryHandler; 388
+Landroid/speech/RecognitionListener; 389
+Ljava/lang/InstantiationException; 390
+Ljava/util/concurrent/ExecutionException; 391
+Landroid/icu/text/DateIntervalInfo;.DIICACHE:Landroid/icu/impl/ICUCache; 392
+Landroid/text/format/DateIntervalFormat;.CACHED_FORMATTERS:Landroid/util/LruCache;.map:Ljava/util/LinkedHashMap; 392
+Landroid/icu/text/DateIntervalFormat;.LOCAL_PATTERN_CACHE:Landroid/icu/impl/ICUCache; 392
+Landroid/icu/impl/OlsonTimeZone; 392
+Landroid/text/format/DateIntervalFormat;.CACHED_FORMATTERS:Landroid/util/LruCache; 392
+Landroid/graphics/drawable/Drawable; 393
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 394
+Landroid/app/Activity; 395
+Landroid/icu/text/PluralRules$KeywordStatus;.INVALID:Landroid/icu/text/PluralRules$KeywordStatus;.name:Ljava/lang/String; 396
+Landroid/net/Uri; 396
+Lsun/util/calendar/CalendarSystem;.calendars:Ljava/util/concurrent/ConcurrentMap; 396
+Landroid/animation/PropertyValuesHolder$IntPropertyValuesHolder;.sJNISetterPropertyMap:Ljava/util/HashMap; 397
+Landroid/graphics/drawable/ShapeDrawable; 398
+Lcom/android/internal/widget/ActionBarContextView; 399
+Landroid/widget/Toolbar$SavedState; 399
+Lcom/android/internal/widget/ActionBarContainer; 399
+Lcom/android/internal/widget/ActionBarOverlayLayout; 399
+Lcom/android/internal/widget/ActionBarContainer$ActionBarBackgroundDrawable; 399
+Landroid/widget/ActionMenuPresenter$OverflowMenuButton; 400
+Landroid/widget/ActionMenuView; 401
+Landroid/content/res/Configuration; 402
+Ljava/util/IdentityHashMap;.NULL_KEY:Ljava/lang/Object; 403
+Ljava/util/concurrent/ForkJoinPool; 404
+Landroid/os/ResultReceiver; 405
+Ljava/util/concurrent/TimeoutException; 406
+Ljava/io/IOException; 407
+Landroid/accounts/AccountAuthenticatorResponse; 408
+Landroid/nfc/NfcAdapter; 409
+Landroid/nfc/NfcAdapter;.sNfcAdapters:Ljava/util/HashMap; 409
+Landroid/app/backup/BackupManager; 410
+Landroid/app/NotificationChannelGroup; 411
+Landroid/content/pm/ParceledListSlice; 411
+Landroid/os/FileObserver; 412
+Landroid/os/UserHandle; 413
+Landroid/content/pm/PackageManager$NameNotFoundException; 414
+[Ljava/lang/Integer; 415
+Landroid/animation/PropertyValuesHolder;.sSetterPropertyMap:Ljava/util/HashMap; 415
+Landroid/content/LocusId; 416
+Landroid/view/contentcapture/ContentCaptureContext; 416
+Landroid/telephony/ims/RegistrationManager;.IMS_REG_TO_ACCESS_TYPE_MAP:Ljava/util/Map;.table:[Ljava/lang/Object;.18:Ljava/lang/Integer; 417
+Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;.pool:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.4:Ljava/util/concurrent/ConcurrentHashMap$Node; 418
+Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;.pool:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node; 418
+Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;.pool:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.2:Ljava/util/concurrent/ConcurrentHashMap$Node;.next:Ljava/util/concurrent/ConcurrentHashMap$Node; 418
+Lcom/android/internal/telephony/cdnr/CarrierDisplayNameResolver;.EF_SOURCE_PRIORITY:Ljava/util/List;.a:[Ljava/lang/Object;.9:Ljava/lang/Integer; 418
+Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;.pool:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.56:Ljava/util/concurrent/ConcurrentHashMap$Node; 418
+Lcom/android/internal/telephony/cdnr/CarrierDisplayNameResolver;.EF_SOURCE_PRIORITY:Ljava/util/List;.a:[Ljava/lang/Object;.5:Ljava/lang/Integer; 418
+Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;.pool:Ljava/util/concurrent/ConcurrentMap; 418
+Landroid/widget/EditText; 419
+Landroid/widget/CheckedTextView; 420
+Landroid/os/strictmode/UnsafeIntentLaunchViolation; 421
+Landroid/app/Service; 422
+Ldalvik/system/BlockGuard; 423
+Landroid/hardware/devicestate/DeviceStateManagerGlobal; 424
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 425
+Landroid/hardware/camera2/marshal/MarshalRegistry;.sMarshalerMap:Ljava/util/HashMap; 425
+Landroid/hardware/camera2/CameraCharacteristics;.LENS_FACING:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 425
+Landroid/content/ClipboardManager$OnPrimaryClipChangedListener; 426
+Landroid/icu/text/BreakIterator;.iterCache:[Landroid/icu/impl/CacheValue; 427
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.13:Ljava/util/WeakHashMap$Entry; 428
+Landroid/icu/text/Collator; 429
+Landroid/icu/impl/number/parse/NanMatcher;.DEFAULT:Landroid/icu/impl/number/parse/NanMatcher;.uniSet:Landroid/icu/text/UnicodeSet;.strings:Ljava/util/SortedSet;.c:Ljava/util/Collection;.m:Ljava/util/NavigableMap; 430
+Ljava/io/FileNotFoundException; 431
+Landroid/os/BaseBundle; 432
+Landroid/service/watchdog/ExplicitHealthCheckService$PackageConfig; 433
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.116:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.12:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.90:Ljava/lang/String; 434
+Landroid/icu/text/MessageFormat;.rootLocale:Ljava/util/Locale;.baseLocale:Lsun/util/locale/BaseLocale;.language:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.385:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.107:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.112:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.480:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.550:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.143:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._obsoleteLanguages:[Ljava/lang/String;.1:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.473:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.138:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.204:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.71:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._replacementCountries:[Ljava/lang/String;.12:Ljava/lang/String; 434
+Landroid/icu/impl/duration/impl/DataRecord$ETimeLimit;.names:[Ljava/lang/String;.1:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._replacementCountries:[Ljava/lang/String;.9:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.99:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages3:[Ljava/lang/String;.152:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.256:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.170:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.220:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.461:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._replacementLanguages:[Ljava/lang/String;.5:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.190:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.157:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._obsoleteCountries:[Ljava/lang/String;.4:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.196:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.117:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.5:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.499:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.199:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.18:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.324:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.101:Ljava/lang/String; 434
+Landroid/icu/impl/locale/UnicodeLocaleExtension;.CA_JAPANESE:Landroid/icu/impl/locale/UnicodeLocaleExtension;._keywords:Ljava/util/SortedMap;.root:Ljava/util/TreeMap$TreeMapEntry;.key:Ljava/lang/Object; 434
+Landroid/icu/impl/LocaleIDs;._replacementCountries:[Ljava/lang/String;.3:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.140:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.105:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.37:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._replacementCountries:[Ljava/lang/String;.5:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.22:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.103:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.412:Ljava/lang/String; 434
+Landroid/icu/impl/duration/impl/DataRecord$EMilliSupport;.names:[Ljava/lang/String;.1:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.124:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.232:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.219:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.179:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.523:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.75:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.486:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.166:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.112:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.119:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.160:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.298:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.257:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.182:Ljava/lang/String; 434
+Landroid/icu/impl/units/UnitPreferences;.measurementSystem:Ljava/util/Map;.m:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.5:Ljava/util/HashMap$Node;.next:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.47:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.180:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.111:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.358:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.96:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._obsoleteLanguages:[Ljava/lang/String;.0:Ljava/lang/String; 434
+Landroid/icu/text/DateFormat;.HOUR_GENERIC_TZ:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.67:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.254:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.222:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.55:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.349:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.16:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.352:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.443:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.478:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.19:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.401:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.137:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.65:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.474:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.168:Ljava/lang/String; 434
+Landroid/icu/impl/units/UnitPreferences;.measurementSystem:Ljava/util/Map;.m:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.15:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.111:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages3:[Ljava/lang/String;.545:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.30:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.469:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.21:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.69:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.56:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.519:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._replacementLanguages:[Ljava/lang/String;.4:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.107:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.290:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.59:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.220:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.186:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.516:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.181:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.199:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.396:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.117:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.227:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.331:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.447:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.151:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.144:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.132:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.230:Ljava/lang/String; 434
+Landroid/icu/text/DateFormat;.MINUTE_SECOND:Ljava/lang/String; 434
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 435
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.head:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 436
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 437
+Landroid/graphics/drawable/ColorStateListDrawable; 438
+Ljava/lang/SecurityException; 439
+Ljava/lang/RuntimeException; 440
+Landroid/media/audiopolicy/AudioProductStrategy; 441
+Landroid/os/PersistableBundle; 442
+Landroid/content/pm/ShortcutInfo; 442
+Landroid/icu/text/TimeZoneFormat;._tzfCache:Landroid/icu/text/TimeZoneFormat$TimeZoneFormatCache;.map:Ljava/util/concurrent/ConcurrentHashMap; 443
+Landroid/graphics/LeakyTypefaceStorage;.sStorage:Ljava/util/ArrayList; 443
+Landroid/graphics/LeakyTypefaceStorage;.sTypefaceMap:Landroid/util/ArrayMap; 443
+Landroid/text/TextWatcher; 444
+Landroid/view/accessibility/AccessibilityManager$TouchExplorationStateChangeListener; 445
+Ljavax/net/SocketFactory; 446
+Ljava/util/Collections; 447
+Ljava/lang/Exception; 448
+Landroid/os/UserManager; 449
+Landroid/os/RemoteException; 450
+Landroid/content/AttributionSource; 451
+Lcom/android/okhttp/internalandroidapi/HttpURLConnectionFactory$DnsAdapter; 452
+Lcom/android/okhttp/Protocol;.HTTP_2:Lcom/android/okhttp/Protocol; 452
+Ljava/net/Inet4Address; 452
+Lcom/android/okhttp/Protocol;.SPDY_3:Lcom/android/okhttp/Protocol; 452
+Lcom/android/okhttp/OkHttpClient; 452
+Landroid/os/storage/VolumeInfo; 453
+Landroid/os/storage/DiskInfo; 453
+Landroid/view/textclassifier/TextLanguage;.EMPTY:Landroid/view/textclassifier/TextLanguage;.mBundle:Landroid/os/Bundle;.mMap:Landroid/util/ArrayMap; 454
+Ljava/nio/file/StandardOpenOption;.WRITE:Ljava/nio/file/StandardOpenOption; 455
+Ljava/nio/file/StandardOpenOption;.APPEND:Ljava/nio/file/StandardOpenOption; 456
+Ljava/util/logging/FileHandler; 457
+Ljava/nio/file/StandardOpenOption;.CREATE_NEW:Ljava/nio/file/StandardOpenOption; 457
+Ljava/util/logging/FileHandler;.locks:Ljava/util/Set;.map:Ljava/util/HashMap; 457
+Lsun/nio/ch/SharedFileLockTable;.queue:Ljava/lang/ref/ReferenceQueue; 458
+Ljavax/net/ServerSocketFactory; 458
+Landroid/os/AsyncTask; 459
+Landroid/os/strictmode/UnbufferedIoViolation; 460
+Landroid/app/usage/AppStandbyInfo; 461
+Landroid/text/format/DateUtils; 462
+Landroid/security/IKeyChainService; 463
+Landroid/util/Log$TerribleFailure; 464
+Lcom/android/internal/os/RuntimeInit$KillApplicationHandler; 464
+Ljava/util/Timer;.nextSerialNumber:Ljava/util/concurrent/atomic/AtomicInteger; 465
+Landroid/telephony/ims/stub/ImsConfigImplBase$ImsConfigStub; 466
+Landroid/telephony/ims/stub/ImsRegistrationImplBase$1; 466
+Landroid/telephony/ims/ImsUtListener; 466
+Landroid/telephony/ims/feature/MmTelFeature$1; 466
+Lcom/android/ims/ImsManager;.IMS_MANAGER_INSTANCES:Landroid/util/SparseArray;.mValues:[Ljava/lang/Object; 467
+Lcom/android/ims/ImsManager;.IMS_MANAGER_INSTANCES:Landroid/util/SparseArray; 467
+Lcom/android/ims/ImsManager;.IMS_MANAGER_INSTANCES:Landroid/util/SparseArray;.mKeys:[I 467
+Landroid/telephony/ims/aidl/IImsConfig$Stub$Proxy; 468
+Landroid/telephony/ims/aidl/IImsRegistration$Stub$Proxy; 468
+Landroid/telephony/NetworkService; 469
+Landroid/telephony/TelephonyCallback$ServiceStateListener; 470
+Landroid/telephony/TelephonyCallback$PhysicalChannelConfigListener; 471
+Landroid/telephony/TelephonyCallback$RadioPowerStateListener; 471
+Lsun/security/x509/X500Name;.internedOIDs:Ljava/util/Map; 472
+Lsun/security/x509/X500Name;.internedOIDs:Ljava/util/Map;.table:[Ljava/util/HashMap$Node; 472
+Landroid/media/MediaCodec; 473
+Ljava/nio/file/StandardOpenOption;.CREATE:Ljava/nio/file/StandardOpenOption; 474
+Ljava/nio/file/NoSuchFileException; 475
+Ljava/text/DateFormatSymbols;.cachedInstances:Ljava/util/concurrent/ConcurrentMap; 476
+Ljava/util/Currency;.instances:Ljava/util/concurrent/ConcurrentMap; 476
+Ljava/util/Calendar;.cachedLocaleData:Ljava/util/concurrent/ConcurrentMap; 476
+Ljava/text/SimpleDateFormat;.cachedNumberFormatData:Ljava/util/concurrent/ConcurrentMap; 476
+Landroid/app/UriGrantsManager;.IUriGrantsManagerSingleton:Landroid/util/Singleton; 477
+Landroid/content/ContentProviderProxy; 478
+Landroid/os/DeadObjectException; 479
+Landroid/app/slice/SliceSpec; 479
+Landroid/database/sqlite/SQLiteDatabase; 480
+Ljava/util/Locale;.CHINA:Ljava/util/Locale; 481
+Ljava/util/Locale;.TAIWAN:Ljava/util/Locale; 481
+Ljava/util/Locale;.KOREA:Ljava/util/Locale; 481
+Ljava/util/Scanner; 482
+Ljava/math/BigDecimal; 483
+Ljava/security/interfaces/RSAPrivateCrtKey; 483
+Ljava/security/interfaces/RSAPrivateKey; 483
+Lcom/android/server/backup/AccountSyncSettingsBackupHelper;.KEY_ACCOUNT_TYPE:Ljava/lang/String; 483
+Landroid/util/UtilConfig; 484
+Ljava/net/ResponseCache; 485
+Landroid/content/ReceiverCallNotAllowedException; 486
+Landroid/app/ReceiverRestrictedContext; 487
+Landroid/os/strictmode/CredentialProtectedWhileLockedViolation; 488
+Landroid/app/Application; 489
+Ljava/util/NoSuchElementException; 490
+Landroid/os/Messenger; 491
+Landroid/telephony/TelephonyCallback$DataEnabledListener; 491
+Landroid/system/StructLinger; 492
diff --git a/core/api/current.txt b/core/api/current.txt
index 7f261d450b42..d1d798346c97 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -428,6 +428,7 @@ package android {
field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final int adServiceTypes;
field public static final int addPrintersActivity = 16843750; // 0x10103e6
field public static final int addStatesFromChildren = 16842992; // 0x10100f0
field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -12606,6 +12607,7 @@ package android.content.pm {
method public boolean isStagedSessionApplied();
method public boolean isStagedSessionFailed();
method public boolean isStagedSessionReady();
+ method @FlaggedApi("android.content.pm.archiving") public boolean isUnarchival();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
field public static final int INVALID_ID = -1; // 0xffffffff
@@ -13296,6 +13298,7 @@ package android.content.pm {
method @NonNull public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
method @IntRange(from=0xffffffff) public long getLongVersion();
method public String getName();
+ method @FlaggedApi("android.content.pm.sdk_lib_independence") @NonNull public java.util.List<android.content.pm.VersionedPackage> getOptionalDependentPackages();
method public int getType();
method @Deprecated @IntRange(from=0xffffffff) public int getVersion();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index e7803fbf011d..d395b8cf936e 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -136,6 +136,7 @@ package android.content {
package android.content.pm {
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+ method @FlaggedApi("android.content.pm.sdk_lib_independence") @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getOptionalSharedLibraryInfos();
method @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraryInfos();
field public static final int HIDDEN_API_ENFORCEMENT_DEFAULT = -1; // 0xffffffff
field public static final int HIDDEN_API_ENFORCEMENT_DISABLED = 0; // 0x0
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 225b31ce37ed..802354e08653 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -9878,8 +9878,8 @@ package android.nfc.cardemulation {
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<java.lang.String> getSubsetAids();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getUid();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean hasCategory(@NonNull String);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean isCategoryOtherServiceEnabled();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean isOnHost();
- method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean isOtherServiceEnabled();
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public CharSequence loadAppLabel(@NonNull android.content.pm.PackageManager);
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.graphics.drawable.Drawable loadBanner(@NonNull android.content.pm.PackageManager);
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.pm.PackageManager);
@@ -9888,9 +9888,9 @@ package android.nfc.cardemulation {
method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresScreenOn();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresUnlock();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void resetOffHostSecureElement();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setCategoryOtherServiceEnabled(boolean);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String);
- method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOtherServiceEnabled(boolean);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR;
}
@@ -12930,6 +12930,7 @@ package android.service.voice {
field public static final int CONFIDENCE_LEVEL_LOW = 1; // 0x1
field public static final int CONFIDENCE_LEVEL_MEDIUM = 2; // 0x2
field public static final int CONFIDENCE_LEVEL_NONE = 0; // 0x0
+ field @FlaggedApi("android.service.voice.flags.allow_hotword_bump_egress") public static final int CONFIDENCE_LEVEL_VERY_HIGH = 4; // 0x4
field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordRejectedResult> CREATOR;
}
@@ -13701,6 +13702,7 @@ package android.telephony {
method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
method public int describeContents();
method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers();
+ method @FlaggedApi("com.android.internal.telephony.flags.carrier_restriction_status") public int getCarrierRestrictionStatus();
method public int getDefaultCarrierRestriction();
method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers();
method public int getMultiSimPolicy();
@@ -14523,7 +14525,6 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void clearRadioPowerOffForReason(int);
method public void dial(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean disableDataConnectivity();
- method @FlaggedApi("com.android.internal.telephony.flags.enable_identifier_disclosure_transparency") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableCellularIdentifierDisclosureNotifications(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableDataConnectivity();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableModemForSlot(int, boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean);
@@ -14596,7 +14597,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
- method @FlaggedApi("com.android.internal.telephony.flags.enable_identifier_disclosure_transparency") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCellularIdentifierDisclosureNotificationEnabled();
+ method @FlaggedApi("com.android.internal.telephony.flags.enable_identifier_disclosure_transparency") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCellularIdentifierDisclosureNotificationsEnabled();
method public boolean isDataConnectivityPossible();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
@@ -14644,6 +14645,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
+ method @FlaggedApi("com.android.internal.telephony.flags.enable_identifier_disclosure_transparency") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setEnableCellularIdentifierDisclosureNotifications(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult setIccLockEnabled(boolean, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabled(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index dec1ee52712d..cef11bb42c3f 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -1909,6 +1909,8 @@ SamShouldBeLast: android.view.accessibility.AccessibilityManager#addAccessibilit
SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addAccessibilityStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.accessibility.AccessibilityManager#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addTouchExplorationStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.view.inputmethod.InputMethodInfo#dump(android.util.Printer, String):
+ SAM-compatible parameters (such as parameter 1, "pw", in android.view.inputmethod.InputMethodInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams):
SAM-compatible parameters (such as parameter 2, "filePathCallback", in android.webkit.WebChromeClient.onShowFileChooser) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4a9fa9e63bf9..5674a108baaa 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3061,10 +3061,10 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Request to put the a freeform activity into fullscreen. This will only be allowed if the
- * activity is on a freeform display, such as a desktop device. The requester has to be the
- * top-most activity of the focused display, and the request should be a response to a user
- * input. When getting fullscreen and receiving corresponding
+ * Request to put the freeform activity into fullscreen. The requester has to be the top-most
+ * activity of the focused display which can be verified using
+ * {@link #onTopResumedActivityChanged(boolean)}. The request should also be a response to a
+ * user input. When getting fullscreen and receiving corresponding
* {@link #onConfigurationChanged(Configuration)} and
* {@link #onMultiWindowModeChanged(boolean, Configuration)}, the activity should relayout
* itself and the system bars' visibilities can be controlled as usual fullscreen apps.
@@ -3072,11 +3072,6 @@ public class Activity extends ContextThemeWrapper
* Calling it again with the exit request can restore the activity to the previous status.
* This will only happen when it got into fullscreen through this API.
*
- * If an app wants to be in fullscreen always, it should claim as not being resizable
- * by setting
- * <a href="https://developer.android.com/guide/topics/large-screens/multi-window-support#resizeableActivity">
- * {@code android:resizableActivity="false"}</a> instead of calling this API.
- *
* @param request Can be {@link #FULLSCREEN_MODE_REQUEST_ENTER} or
* {@link #FULLSCREEN_MODE_REQUEST_EXIT} to indicate this request is to get
* fullscreen or get restored.
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 87c86df6140d..287d2bd9e6a7 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2909,7 +2909,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
launcherExtras, dialogInfo, flags, mContext.getOpPackageName(),
- getUserId());
+ UserHandle.myUserId() /* suspendingUserId */, getUserId() /* targetUserId */);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 53a21cdd78c9..343348b89625 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -645,8 +645,8 @@ public final class AutomaticZenRule implements Parcelable {
}
public Builder(@NonNull String name, @NonNull Uri conditionId) {
- mName = name;
- mConditionId = conditionId;
+ mName = Objects.requireNonNull(name);
+ mConditionId = Objects.requireNonNull(conditionId);
}
/**
diff --git a/core/java/android/app/FullscreenRequestHandler.java b/core/java/android/app/FullscreenRequestHandler.java
index 52f461daf233..c78c66aa62c0 100644
--- a/core/java/android/app/FullscreenRequestHandler.java
+++ b/core/java/android/app/FullscreenRequestHandler.java
@@ -16,8 +16,7 @@
package android.app;
-import static android.app.Activity.FULLSCREEN_MODE_REQUEST_ENTER;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.Activity.FULLSCREEN_MODE_REQUEST_EXIT;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import android.annotation.IntDef;
@@ -35,18 +34,14 @@ import android.os.OutcomeReceiver;
public class FullscreenRequestHandler {
@IntDef(prefix = { "RESULT_" }, value = {
RESULT_APPROVED,
- RESULT_FAILED_NOT_IN_FREEFORM,
RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY,
- RESULT_FAILED_NOT_DEFAULT_FREEFORM,
RESULT_FAILED_NOT_TOP_FOCUSED
})
public @interface RequestResult {}
public static final int RESULT_APPROVED = 0;
- public static final int RESULT_FAILED_NOT_IN_FREEFORM = 1;
- public static final int RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY = 2;
- public static final int RESULT_FAILED_NOT_DEFAULT_FREEFORM = 3;
- public static final int RESULT_FAILED_NOT_TOP_FOCUSED = 4;
+ public static final int RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY = 1;
+ public static final int RESULT_FAILED_NOT_TOP_FOCUSED = 2;
public static final String REMOTE_CALLBACK_RESULT_KEY = "result";
@@ -85,17 +80,10 @@ public class FullscreenRequestHandler {
OutcomeReceiver<Void, Throwable> callback, int result) {
Throwable e = null;
switch (result) {
- case RESULT_FAILED_NOT_IN_FREEFORM:
- e = new IllegalStateException("The window is not a freeform window, the request "
- + "to get into fullscreen cannot be approved.");
- break;
case RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY:
e = new IllegalStateException("The window is not in fullscreen by calling the "
+ "requestFullscreenMode API before, such that cannot be restored.");
break;
- case RESULT_FAILED_NOT_DEFAULT_FREEFORM:
- e = new IllegalStateException("The window is not launched in freeform by default.");
- break;
case RESULT_FAILED_NOT_TOP_FOCUSED:
e = new IllegalStateException("The window is not the top focused window.");
break;
@@ -109,11 +97,7 @@ public class FullscreenRequestHandler {
}
private static int earlyCheckRequestMatchesWindowingMode(int request, int windowingMode) {
- if (request == FULLSCREEN_MODE_REQUEST_ENTER) {
- if (windowingMode != WINDOWING_MODE_FREEFORM) {
- return RESULT_FAILED_NOT_IN_FREEFORM;
- }
- } else {
+ if (request == FULLSCREEN_MODE_REQUEST_EXIT) {
if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
return RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY;
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 16a80e93326a..3713380485ea 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -19,6 +19,7 @@ package android.content.pm;
import static android.os.Build.VERSION_CODES.DONUT;
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1065,11 +1066,25 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
* the structure.
*
+ * NOTE: the list also contains the result of {@link #getOptionalSharedLibraryInfos}.
+ *
* {@hide}
*/
+ @Nullable
public List<SharedLibraryInfo> sharedLibraryInfos;
/**
+ * List of all shared libraries this application is optionally linked against.
+ * This field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
+ * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
+ * the structure.
+ *
+ * @hide
+ */
+ @Nullable
+ public List<SharedLibraryInfo> optionalSharedLibraryInfos;
+
+ /**
* Full path to the default directory assigned to the package for its
* persistent data.
*/
@@ -1937,6 +1952,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
seInfoUser = orig.seInfoUser;
sharedLibraryFiles = orig.sharedLibraryFiles;
sharedLibraryInfos = orig.sharedLibraryInfos;
+ optionalSharedLibraryInfos = orig.optionalSharedLibraryInfos;
dataDir = orig.dataDir;
deviceProtectedDataDir = orig.deviceProtectedDataDir;
credentialProtectedDataDir = orig.credentialProtectedDataDir;
@@ -2029,6 +2045,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeString8(seInfoUser);
dest.writeString8Array(sharedLibraryFiles);
dest.writeTypedList(sharedLibraryInfos);
+ dest.writeTypedList(optionalSharedLibraryInfos);
dest.writeString8(dataDir);
dest.writeString8(deviceProtectedDataDir);
dest.writeString8(credentialProtectedDataDir);
@@ -2129,6 +2146,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
seInfoUser = source.readString8();
sharedLibraryFiles = source.createString8Array();
sharedLibraryInfos = source.createTypedArrayList(SharedLibraryInfo.CREATOR);
+ optionalSharedLibraryInfos = source.createTypedArrayList(SharedLibraryInfo.CREATOR);
dataDir = source.readString8();
deviceProtectedDataDir = source.readString8();
credentialProtectedDataDir = source.readString8();
@@ -2760,6 +2778,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* list will only be set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
* PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving the structure.
*
+ * NOTE: the list also contains the result of {@link #getOptionalSharedLibraryInfos}.
+ *
* @hide
*/
@NonNull
@@ -2772,6 +2792,23 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
/**
+ * List of all shared libraries this application is optionally linked against. This
+ * list will only be set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
+ * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving the structure.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @FlaggedApi(Flags.FLAG_SDK_LIB_INDEPENDENCE)
+ public List<SharedLibraryInfo> getOptionalSharedLibraryInfos() {
+ if (optionalSharedLibraryInfos == null) {
+ return Collections.EMPTY_LIST;
+ }
+ return optionalSharedLibraryInfos;
+ }
+
+ /**
* Gets the trusted host certificate digests of apps that are allowed to embed activities of
* this application. The digests are computed using the SHA-256 digest algorithm.
* @see android.R.attr#knownActivityEmbeddingCerts
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 6f7299aa8e31..a97de6368b8c 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -65,6 +65,8 @@ interface ILauncherApps {
in UserHandle user);
LauncherUserInfo getLauncherUserInfo(in UserHandle user);
List<String> getPreInstalledSystemPackages(in UserHandle user);
+ IntentSender getAppMarketActivityIntent(String callingPackage, String packageName,
+ in UserHandle user);
void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
String callingFeatureId, in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 98623de810c4..6dc8d4738c87 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -300,7 +300,8 @@ interface IPackageManager {
String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
in PersistableBundle appExtras, in PersistableBundle launcherExtras,
- in SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId);
+ in SuspendDialogInfo dialogInfo, int flags, String suspendingPackage,
+ int suspendingUserId, int targetUserId);
String[] getUnsuspendablePackagesForUser(in String[] packageNames, int userId);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index ccc8f0956865..1d2b1aff46bc 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -799,6 +799,55 @@ public class LauncherApps {
}
}
+
+ /**
+ * Returns an intent sender which can be used to start the App Market activity (Installer
+ * Activity).
+ * This method is primarily used to get an intent sender which starts App Market activity for
+ * another profile, if the caller is not otherwise allowed to start activity in that profile.
+ *
+ * <p>When packageName is set, intent sender to start the App Market Activity which installed
+ * the package in calling user will be returned, but for the profile passed.
+ *
+ * <p>When packageName is not set, intent sender to launch the default App Market Activity for
+ * the profile will be returned. In case there are multiple App Market Activities available for
+ * the profile, IntentPicker will be started, allowing user to choose the preferred activity.
+ *
+ * <p>The method will fall back to the behaviour of not having the packageName set, in case:
+ * <ul>
+ * <li>No activity for the packageName is found in calling user-space.</li>
+ * <li>The App Market Activity which installed the package in calling user-space is not
+ * present.</li>
+ * <li>The App Market Activity which installed the package in calling user-space is not
+ * present in the profile passed.</li>
+ * </ul>
+ * </p>
+ *
+ *
+ *
+ * @param packageName the package for which intent sender to launch App Market Activity is
+ * required.
+ * @param user the profile for which intent sender to launch App Market Activity is required.
+ * @return {@link IntentSender} object which launches the App Market Activity, null in case
+ * there is no such activity.
+ * @hide
+ */
+ @Nullable
+ @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
+ public IntentSender getAppMarketActivityIntent(@Nullable String packageName,
+ @NonNull UserHandle user) {
+ if (DEBUG) {
+ Log.i(TAG, "getAppMarketActivityIntent for package: " + packageName
+ + " user: " + user);
+ }
+ try {
+ return mService.getAppMarketActivityIntent(mContext.getPackageName(),
+ packageName, user);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
/**
* Returns the list of the system packages that are installed at user creation.
*
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index e395127dfaf3..0e131b413d0c 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -4381,6 +4381,17 @@ public class PackageInstaller {
return pendingUserActionReason;
}
+ /**
+ * Returns true if the session is an unarchival.
+ *
+ * @see PackageInstaller#requestUnarchive
+ */
+ @FlaggedApi(Flags.FLAG_ARCHIVING)
+ public boolean isUnarchival() {
+ return (installFlags & PackageManager.INSTALL_UNARCHIVE) != 0;
+ }
+
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a5d16f2f6be1..a8638708824b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1517,6 +1517,7 @@ public abstract class PackageManager {
INSTALL_REQUEST_UPDATE_OWNERSHIP,
INSTALL_IGNORE_DEXOPT_PROFILE,
INSTALL_UNARCHIVE_DRAFT,
+ INSTALL_UNARCHIVE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallFlags {}
@@ -1764,13 +1765,22 @@ public abstract class PackageManager {
* If set, then the session is a draft session created for an upcoming unarchival by its
* installer.
*
- * @see PackageInstaller#requestUnarchive(String)
+ * @see PackageInstaller#requestUnarchive
*
* @hide
*/
public static final int INSTALL_UNARCHIVE_DRAFT = 1 << 29;
/**
+ * If set, then the {@link PackageInstaller.Session} is an unarchival.
+ *
+ * @see PackageInstaller#requestUnarchive
+ *
+ * @hide
+ */
+ public static final int INSTALL_UNARCHIVE = 1 << 30;
+
+ /**
* Flag parameter for {@link #installPackage} to force a non-staged update of an APEX. This is
* a development-only feature and should not be used on end user devices.
*
@@ -9990,6 +10000,9 @@ public abstract class PackageManager {
* device administrators or apps holding {@link android.Manifest.permission#MANAGE_USERS} or
* {@link android.Manifest.permission#SUSPEND_APPS}.
*
+ * <p>
+ * <strong>Note:</strong>This API doesn't support cross user suspension and should only be used
+ * for testing.
* @param suspendedPackage The package that has been suspended.
* @return Name of the package that suspended the given package. Returns {@code null} if the
* given package is not currently suspended and the platform package name - i.e.
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 25ba72551b04..5acebf54a159 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -23,6 +24,7 @@ import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Pair;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -99,26 +101,61 @@ public final class SharedLibraryInfo implements Parcelable {
private final boolean mIsNative;
private final VersionedPackage mDeclaringPackage;
private final List<VersionedPackage> mDependentPackages;
+
+ private final List<VersionedPackage> mOptionalDependentPackages;
private List<SharedLibraryInfo> mDependencies;
/**
* Creates a new instance.
*
+ * @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of
+ * jars of
+ * this shared library. Null for builtin library.
+ * @param name The lib name.
+ * @param version The lib version if not builtin.
+ * @param type The lib type.
+ * @param declaringPackage The package that declares the library.
+ * @param dependentPackages The packages that depend on the library.
+ * @param isNative indicate if this shared lib is a native lib or not (i.e. java)
+ * @hide
+ */
+ public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
+ String name, long version, int type,
+ VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
+ List<SharedLibraryInfo> dependencies, boolean isNative) {
+ mPath = path;
+ mPackageName = packageName;
+ mCodePaths = codePaths;
+ mName = name;
+ mVersion = version;
+ mType = type;
+ mDeclaringPackage = declaringPackage;
+ mDependentPackages = dependentPackages;
+ mDependencies = dependencies;
+ mIsNative = isNative;
+ mOptionalDependentPackages = null;
+ }
+
+ /**
+ * Creates a new instance.
+ *
* @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of jars of
* this shared library. Null for builtin library.
* @param name The lib name.
* @param version The lib version if not builtin.
* @param type The lib type.
* @param declaringPackage The package that declares the library.
- * @param dependentPackages The packages that depend on the library.
* @param isNative indicate if this shared lib is a native lib or not (i.e. java)
+ * @param allDependentPackages All packages that depend on the library (including the optional
+ * sdk libraries).
*
* @hide
*/
public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
String name, long version, int type,
- VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
- List<SharedLibraryInfo> dependencies, boolean isNative) {
+ VersionedPackage declaringPackage,
+ List<SharedLibraryInfo> dependencies, boolean isNative,
+ Pair<List<VersionedPackage>, List<Boolean>> allDependentPackages) {
mPath = path;
mPackageName = packageName;
mCodePaths = codePaths;
@@ -126,9 +163,28 @@ public final class SharedLibraryInfo implements Parcelable {
mVersion = version;
mType = type;
mDeclaringPackage = declaringPackage;
- mDependentPackages = dependentPackages;
mDependencies = dependencies;
mIsNative = isNative;
+
+ var allDependents = allDependentPackages.first;
+ var usesLibOptional = allDependentPackages.second;
+ mDependentPackages = allDependents;
+ List<VersionedPackage> optionalDependents = null;
+ if (mType == SharedLibraryInfo.TYPE_SDK_PACKAGE
+ && Flags.sdkLibIndependence() && allDependents != null
+ && usesLibOptional != null
+ && allDependents.size() == usesLibOptional.size()) {
+ for (int k = 0; k < allDependents.size(); k++) {
+ VersionedPackage versionedPackage = allDependents.get(k);
+ if (usesLibOptional.get(k)) {
+ if (optionalDependents == null) {
+ optionalDependents = new ArrayList<>();
+ }
+ optionalDependents.add(versionedPackage);
+ }
+ }
+ }
+ mOptionalDependentPackages = optionalDependents;
}
private SharedLibraryInfo(Parcel parcel) {
@@ -148,6 +204,8 @@ public final class SharedLibraryInfo implements Parcelable {
parcel.readArrayList(null, android.content.pm.VersionedPackage.class);
mDependencies = parcel.createTypedArrayList(SharedLibraryInfo.CREATOR);
mIsNative = parcel.readBoolean();
+ mOptionalDependentPackages = parcel.readParcelableList(new ArrayList<>(),
+ VersionedPackage.class.getClassLoader(), VersionedPackage.class);
}
/**
@@ -324,6 +382,8 @@ public final class SharedLibraryInfo implements Parcelable {
/**
* Gets the packages that depend on the library.
*
+ * NOTE: the list also contains the result of {@link #getOptionalDependentPackages}.
+ *
* @return The dependent packages.
*/
public @NonNull List<VersionedPackage> getDependentPackages() {
@@ -333,6 +393,19 @@ public final class SharedLibraryInfo implements Parcelable {
return mDependentPackages;
}
+ /**
+ * Gets the packages that optionally depend on the library.
+ *
+ * @return The dependent packages.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_LIB_INDEPENDENCE)
+ public @NonNull List<VersionedPackage> getOptionalDependentPackages() {
+ if (mOptionalDependentPackages == null) {
+ return Collections.emptyList();
+ }
+ return mOptionalDependentPackages;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -362,6 +435,7 @@ public final class SharedLibraryInfo implements Parcelable {
parcel.writeList(mDependentPackages);
parcel.writeTypedList(mDependencies);
parcel.writeBoolean(mIsNative);
+ parcel.writeParcelableList(mOptionalDependentPackages, flags);
}
private static String typeToString(int type) {
diff --git a/core/java/android/hardware/biometrics/AuthenticationStateListener.aidl b/core/java/android/hardware/biometrics/AuthenticationStateListener.aidl
new file mode 100644
index 000000000000..73ac333cfd89
--- /dev/null
+++ b/core/java/android/hardware/biometrics/AuthenticationStateListener.aidl
@@ -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 android.hardware.biometrics;
+
+/**
+ * Low-level callback interface between <Biometric>Manager and <Auth>Service. Allows core system
+ * services (e.g. SystemUI) to register a listener for updates about the current state of biometric
+ * authentication.
+ * @hide
+ */
+oneway interface AuthenticationStateListener {
+ /**
+ * Defines behavior in response to authentication starting
+ * @param requestReason reason from [BiometricRequestConstants.RequestReason] for requesting
+ * authentication starting
+ */
+ void onAuthenticationStarted(int requestReason);
+
+ /**
+ * Defines behavior in response to authentication stopping
+ */
+ void onAuthenticationStopped();
+}
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index f82f79eba8c9..d7d1d1a7c677 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -552,6 +552,44 @@ public class BiometricManager {
}
/**
+ * Registers listener for changes to biometric authentication state.
+ * Only sends callbacks for events that occur after the callback has been registered.
+ * @param listener Listener for changes to biometric authentication state
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void registerAuthenticationStateListener(AuthenticationStateListener listener) {
+ if (mService != null) {
+ try {
+ mService.registerAuthenticationStateListener(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "registerAuthenticationStateListener(): Service not connected");
+ }
+ }
+
+ /**
+ * Unregisters listener for changes to biometric authentication state.
+ * @param listener Listener for changes to biometric authentication state
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void unregisterAuthenticationStateListener(AuthenticationStateListener listener) {
+ if (mService != null) {
+ try {
+ mService.unregisterAuthenticationStateListener(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "unregisterAuthenticationStateListener(): Service not connected");
+ }
+ }
+
+
+ /**
* Requests all {@link Authenticators.Types#BIOMETRIC_STRONG} sensors to have their
* authenticatorId invalidated for the specified user. This happens when enrollments have been
* added on devices with multiple biometric sensors.
diff --git a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java b/core/java/android/hardware/biometrics/BiometricRequestConstants.java
index 065ae64a92ad..b036f309f7df 100644
--- a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricRequestConstants.java
@@ -22,24 +22,27 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Common constants for biometric overlays.
+ * Common constants for biometric requests.
* @hide
*/
-public interface BiometricOverlayConstants {
+public class BiometricRequestConstants {
+
+ private BiometricRequestConstants() {}
+
/** Unknown usage. */
- int REASON_UNKNOWN = 0;
+ public static final int REASON_UNKNOWN = 0;
/** User is about to enroll. */
- int REASON_ENROLL_FIND_SENSOR = 1;
+ public static final int REASON_ENROLL_FIND_SENSOR = 1;
/** User is enrolling. */
- int REASON_ENROLL_ENROLLING = 2;
+ public static final int REASON_ENROLL_ENROLLING = 2;
/** Usage from BiometricPrompt. */
- int REASON_AUTH_BP = 3;
- /** Usage from Keyguard. */
- int REASON_AUTH_KEYGUARD = 4;
+ public static final int REASON_AUTH_BP = 3;
+ /** Usage from Device Entry. */
+ public static final int REASON_AUTH_KEYGUARD = 4;
/** Non-specific usage (from FingerprintManager). */
- int REASON_AUTH_OTHER = 5;
+ public static final int REASON_AUTH_OTHER = 5;
/** Usage from Settings. */
- int REASON_AUTH_SETTINGS = 6;
+ public static final int REASON_AUTH_SETTINGS = 6;
@IntDef({REASON_UNKNOWN,
REASON_ENROLL_FIND_SENSOR,
@@ -49,5 +52,5 @@ public interface BiometricOverlayConstants {
REASON_AUTH_OTHER,
REASON_AUTH_SETTINGS})
@Retention(RetentionPolicy.SOURCE)
- @interface ShowReason {}
+ public @interface RequestReason {}
}
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index 5bdbe2b573b2..8514f98fbf0d 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -16,6 +16,7 @@
package android.hardware.biometrics;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IInvalidationCallback;
@@ -66,6 +67,12 @@ interface IAuthService {
// Register callback for when keyguard biometric eligibility changes.
void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
+ // Register listener for changes to authentication state.
+ void registerAuthenticationStateListener(AuthenticationStateListener listener);
+
+ // Unregister listener for changes to authentication state.
+ void unregisterAuthenticationStateListener(AuthenticationStateListener listener);
+
// Requests all BIOMETRIC_STRONG sensors to have their authenticatorId invalidated for the
// specified user. This happens when enrollments have been added on devices with multiple
// biometric sensors.
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 935157a48a45..fe7de8333784 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -983,6 +983,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/**
* @hide
*/
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 0100660669e9..f594c00b0e47 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -15,6 +15,7 @@
*/
package android.hardware.fingerprint;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricStateListener;
@@ -203,6 +204,14 @@ interface IFingerprintService {
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void setSidefpsController(in ISidefpsController controller);
+ // Registers AuthenticationStateListener.
+ @EnforcePermission("USE_BIOMETRIC_INTERNAL")
+ void registerAuthenticationStateListener(AuthenticationStateListener listener);
+
+ // Unregisters AuthenticationStateListener.
+ @EnforcePermission("USE_BIOMETRIC_INTERNAL")
+ void unregisterAuthenticationStateListener(AuthenticationStateListener listener);
+
// Registers BiometricStateListener.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void registerBiometricStateListener(IBiometricStateListener listener);
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 98a980f5e7f8..f407fb73534f 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -284,6 +284,20 @@ public final class NfcAdapter {
public static final int STATE_TURNING_OFF = 4;
/**
+ * Possible states from {@link #getAdapterState}.
+ *
+ * @hide
+ */
+ @IntDef(prefix = { "STATE_" }, value = {
+ STATE_OFF,
+ STATE_TURNING_ON,
+ STATE_ON,
+ STATE_TURNING_OFF
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AdapterState{}
+
+ /**
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
* Setting this flag enables polling for Nfc-A technology.
@@ -948,7 +962,7 @@ public final class NfcAdapter {
*/
@SystemApi
@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- public int getAdapterState() {
+ public @AdapterState int getAdapterState() {
try {
return sService.getState();
} catch (RemoteException e) {
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index e331c95288d9..bd087f970426 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -130,7 +130,7 @@ public final class ApduServiceInfo implements Parcelable {
/**
* State of the service for CATEGORY_OTHER selection
*/
- private boolean mOtherServiceEnabled;
+ private boolean mCategoryOtherServiceEnabled;
/**
* @hide
@@ -183,7 +183,7 @@ public final class ApduServiceInfo implements Parcelable {
this.mBannerResourceId = bannerResource;
this.mUid = uid;
this.mSettingsActivityName = settingsActivityName;
- this.mOtherServiceEnabled = isEnabled;
+ this.mCategoryOtherServiceEnabled = isEnabled;
}
@@ -374,7 +374,7 @@ public final class ApduServiceInfo implements Parcelable {
// Set uid
mUid = si.applicationInfo.uid;
- mOtherServiceEnabled = false; // support other category
+ mCategoryOtherServiceEnabled = false; // support other category
}
@@ -746,7 +746,7 @@ public final class ApduServiceInfo implements Parcelable {
dest.writeInt(mUid);
dest.writeString(mSettingsActivityName);
- dest.writeInt(mOtherServiceEnabled ? 1 : 0);
+ dest.writeInt(mCategoryOtherServiceEnabled ? 1 : 0);
};
@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@@ -809,7 +809,7 @@ public final class ApduServiceInfo implements Parcelable {
pw.println(" Static AID groups:");
for (AidGroup group : mStaticAidGroups.values()) {
pw.println(" Category: " + group.getCategory()
- + "(enabled: " + mOtherServiceEnabled + ")");
+ + "(enabled: " + mCategoryOtherServiceEnabled + ")");
for (String aid : group.getAids()) {
pw.println(" AID: " + aid);
}
@@ -817,7 +817,7 @@ public final class ApduServiceInfo implements Parcelable {
pw.println(" Dynamic AID groups:");
for (AidGroup group : mDynamicAidGroups.values()) {
pw.println(" Category: " + group.getCategory()
- + "(enabled: " + mOtherServiceEnabled + ")");
+ + "(enabled: " + mCategoryOtherServiceEnabled + ")");
for (String aid : group.getAids()) {
pw.println(" AID: " + aid);
}
@@ -834,8 +834,8 @@ public final class ApduServiceInfo implements Parcelable {
* @param enabled true to indicate if user has enabled this service
*/
@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- public void setOtherServiceEnabled(boolean enabled) {
- mOtherServiceEnabled = enabled;
+ public void setCategoryOtherServiceEnabled(boolean enabled) {
+ mCategoryOtherServiceEnabled = enabled;
}
@@ -845,8 +845,8 @@ public final class ApduServiceInfo implements Parcelable {
* @return true to indicate if user has enabled this service
*/
@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- public boolean isOtherServiceEnabled() {
- return mOtherServiceEnabled;
+ public boolean isCategoryOtherServiceEnabled() {
+ return mCategoryOtherServiceEnabled;
}
/**
diff --git a/core/java/android/service/voice/HotwordRejectedResult.java b/core/java/android/service/voice/HotwordRejectedResult.java
index 26c1ca428c3b..eb1ac67719ed 100644
--- a/core/java/android/service/voice/HotwordRejectedResult.java
+++ b/core/java/android/service/voice/HotwordRejectedResult.java
@@ -16,9 +16,11 @@
package android.service.voice;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.os.Parcelable;
+import android.service.voice.flags.Flags;
import com.android.internal.util.DataClass;
@@ -53,12 +55,17 @@ public final class HotwordRejectedResult implements Parcelable {
/** High confidence in hotword detector result. */
public static final int CONFIDENCE_LEVEL_HIGH = 3;
+ /** Very high confidence in hotword detector result. **/
+ @FlaggedApi(Flags.FLAG_ALLOW_HOTWORD_BUMP_EGRESS)
+ public static final int CONFIDENCE_LEVEL_VERY_HIGH = 4;
+
/** @hide */
@IntDef(prefix = {"CONFIDENCE_LEVEL_"}, value = {
CONFIDENCE_LEVEL_NONE,
CONFIDENCE_LEVEL_LOW,
CONFIDENCE_LEVEL_MEDIUM,
- CONFIDENCE_LEVEL_HIGH
+ CONFIDENCE_LEVEL_HIGH,
+ CONFIDENCE_LEVEL_VERY_HIGH
})
@Retention(RetentionPolicy.SOURCE)
@interface HotwordConfidenceLevelValue {
@@ -91,9 +98,10 @@ public final class HotwordRejectedResult implements Parcelable {
CONFIDENCE_LEVEL_NONE,
CONFIDENCE_LEVEL_LOW,
CONFIDENCE_LEVEL_MEDIUM,
- CONFIDENCE_LEVEL_HIGH
+ CONFIDENCE_LEVEL_HIGH,
+ CONFIDENCE_LEVEL_VERY_HIGH
})
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
public @interface ConfidenceLevel {}
@@ -109,6 +117,8 @@ public final class HotwordRejectedResult implements Parcelable {
return "CONFIDENCE_LEVEL_MEDIUM";
case CONFIDENCE_LEVEL_HIGH:
return "CONFIDENCE_LEVEL_HIGH";
+ case CONFIDENCE_LEVEL_VERY_HIGH:
+ return "CONFIDENCE_LEVEL_VERY_HIGH";
default: return Integer.toHexString(value);
}
}
@@ -259,10 +269,10 @@ public final class HotwordRejectedResult implements Parcelable {
}
@DataClass.Generated(
- time = 1621961370106L,
+ time = 1701990933632L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordRejectedResult.java",
- inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_HIGH\nprivate final @android.service.voice.HotwordRejectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate static int defaultConfidenceLevel()\nclass HotwordRejectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final @android.annotation.FlaggedApi int CONFIDENCE_LEVEL_VERY_HIGH\nprivate final @android.service.voice.HotwordRejectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate static int defaultConfidenceLevel()\nclass HotwordRejectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/voice/flags/flags.aconfig b/core/java/android/service/voice/flags/flags.aconfig
index c414ef8a6826..b596666bf607 100644
--- a/core/java/android/service/voice/flags/flags.aconfig
+++ b/core/java/android/service/voice/flags/flags.aconfig
@@ -6,3 +6,10 @@ flag {
description: "This flag allows the hotword detection service to egress training data to the default assistant."
bug: "296074924"
}
+
+flag {
+ name: "allow_hotword_bump_egress"
+ namespace: "machine_learning"
+ description: "This flag allows hotword detection service to egress reason code for hotword bump."
+ bug: "290951024"
+}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c7e180732fd4..e3d9c605ff63 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -592,6 +592,13 @@ public interface WindowManager extends ViewManager {
int TRANSIT_FLAG_KEYGUARD_UNOCCLUDING = (1 << 13); // 0x2000
/**
+ * Transition flag: Indicates that there is a physical display switch
+ * TODO(b/316112906) remove after defer_display_updates flag roll out
+ * @hide
+ */
+ int TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH = (1 << 14); // 0x4000
+
+ /**
* @hide
*/
@IntDef(flag = true, prefix = { "TRANSIT_FLAG_" }, value = {
@@ -608,7 +615,8 @@ public interface WindowManager extends ViewManager {
TRANSIT_FLAG_INVISIBLE,
TRANSIT_FLAG_KEYGUARD_APPEARING,
TRANSIT_FLAG_KEYGUARD_OCCLUDING,
- TRANSIT_FLAG_KEYGUARD_UNOCCLUDING
+ TRANSIT_FLAG_KEYGUARD_UNOCCLUDING,
+ TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH,
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionFlags {}
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index efc1455ecd45..f1aa330f562c 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -39,6 +39,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -308,7 +309,8 @@ public class SuspendedAppActivity extends AlertActivity
try {
final String[] errored = ipm.setPackagesSuspendedAsUser(
new String[]{mSuspendedPackage}, false, null, null, null, 0,
- mSuspendingPackage, mUserId);
+ mSuspendingPackage, mUserId /* suspendingUserId */,
+ mUserId /* targetUserId */);
if (ArrayUtils.contains(errored, mSuspendedPackage)) {
Slog.e(TAG, "Could not unsuspend " + mSuspendedPackage);
break;
@@ -350,17 +352,18 @@ public class SuspendedAppActivity extends AlertActivity
}
public static Intent createSuspendedAppInterceptIntent(String suspendedPackage,
- String suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options,
+ UserPackage suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options,
IntentSender onUnsuspend, int userId) {
- return new Intent()
+ Intent intent = new Intent()
.setClassName("android", SuspendedAppActivity.class.getName())
.putExtra(EXTRA_SUSPENDED_PACKAGE, suspendedPackage)
.putExtra(EXTRA_DIALOG_INFO, dialogInfo)
- .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage)
+ .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage.packageName)
.putExtra(EXTRA_UNSUSPEND_INTENT, onUnsuspend)
.putExtra(EXTRA_ACTIVITY_OPTIONS, options)
.putExtra(Intent.EXTRA_USER_ID, userId)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ return intent;
}
}
diff --git a/core/java/com/android/internal/net/TEST_MAPPING b/core/java/com/android/internal/net/TEST_MAPPING
index 971ad36eecba..f935946c95c7 100644
--- a/core/java/com/android/internal/net/TEST_MAPPING
+++ b/core/java/com/android/internal/net/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "postsubmit": [
+ "presubmit": [
{
"name": "FrameworksNetTests",
"options": [
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index f7e1f7293ac6..83acc47d637f 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -726,26 +726,11 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
this.usesSdkLibrariesVersionsMajor, versionMajor, true);
this.usesSdkLibrariesCertDigests = ArrayUtils.appendElement(String[].class,
this.usesSdkLibrariesCertDigests, certSha256Digests, true);
- this.usesSdkLibrariesOptional = appendBoolean(this.usesSdkLibrariesOptional,
+ this.usesSdkLibrariesOptional = ArrayUtils.appendBoolean(this.usesSdkLibrariesOptional,
usesSdkLibrariesOptional);
return this;
}
- /**
- * Adds value to given array if not already present, providing set-like
- * behavior.
- */
- public static boolean[] appendBoolean(@Nullable boolean[] cur, boolean val) {
- if (cur == null) {
- return new boolean[] { val };
- }
- final int N = cur.length;
- boolean[] ret = new boolean[N + 1];
- System.arraycopy(cur, 0, ret, 0, N);
- ret[N] = val;
- return ret;
- }
-
@Override
public PackageImpl addUsesStaticLibrary(String libraryName, long version,
String[] certSha256Digests) {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 9d0be4bf8ee6..8f00f79e7179 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -623,6 +623,21 @@ public class ArrayUtils {
* Adds value to given array if not already present, providing set-like
* behavior.
*/
+ public static boolean[] appendBoolean(@Nullable boolean[] cur, boolean val) {
+ if (cur == null) {
+ return new boolean[] { val };
+ }
+ final int N = cur.length;
+ boolean[] ret = new boolean[N + 1];
+ System.arraycopy(cur, 0, ret, 0, N);
+ ret[N] = val;
+ return ret;
+ }
+
+ /**
+ * Adds value to given array if not already present, providing set-like
+ * behavior.
+ */
public static @NonNull long[] appendLong(@Nullable long[] cur, long val) {
return appendLong(cur, val, false);
}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 91dfc6023e42..55100a5347fd 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -282,6 +282,11 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin
void android_os_Process_setProcessFrozen(
JNIEnv *env, jobject clazz, jint pid, jint uid, jboolean freeze)
{
+ if (uid < 0) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "uid is negative: %d", uid);
+ return;
+ }
+
bool success = true;
if (freeze) {
@@ -305,6 +310,11 @@ jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid)
}
jint android_os_Process_createProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid) {
+ if (uid < 0) {
+ return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "uid is negative: %d", uid);
+ }
+
return createProcessGroup(uid, pid);
}
@@ -590,12 +600,21 @@ void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name)
jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid)
{
+ if (uid < 0) {
+ return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "uid is negative: %d", uid);
+ }
+
return setuid(uid) == 0 ? 0 : errno;
}
-jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid)
-{
- return setgid(uid) == 0 ? 0 : errno;
+jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint gid) {
+ if (gid < 0) {
+ return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "gid is negative: %d", gid);
+ }
+
+ return setgid(gid) == 0 ? 0 : errno;
}
static int pid_compare(const void* v1, const void* v2)
@@ -1235,11 +1254,21 @@ jintArray android_os_Process_getPidsForCommands(JNIEnv* env, jobject clazz,
jint android_os_Process_killProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid)
{
+ if (uid < 0) {
+ return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "uid is negative: %d", uid);
+ }
+
return killProcessGroup(uid, pid, SIGKILL);
}
jint android_os_Process_sendSignalToProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid,
jint signal) {
+ if (uid < 0) {
+ return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "uid is negative: %d", uid);
+ }
+
return sendSignalToProcessGroup(uid, pid, signal);
}
@@ -1258,6 +1287,11 @@ static jint android_os_Process_nativePidFdOpen(JNIEnv* env, jobject, jint pid, j
}
void android_os_Process_freezeCgroupUID(JNIEnv* env, jobject clazz, jint uid, jboolean freeze) {
+ if (uid < 0) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "uid is negative: %d", uid);
+ return;
+ }
+
bool success = true;
if (freeze) {
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e1c1a42eed81..5cfb1a3e44ba 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9802,6 +9802,17 @@
<attr name="supportedTypes" format="reference" />
</declare-styleable>
+ <!-- Use <code>tv-ad-service</code> as the root tag of the XML resource that describes a
+ android.media.tv.ad.TvAdService, which is referenced from its
+ android.media.tv.ad.TvAdService#SERVICE_META_DATA meta-data entry. Described here
+ are the attributes that can be included in that tag. -->
+ <declare-styleable name="TvAdService">
+ <!-- The advertisement types that the TV ad service supports.
+ Reference to a string array resource that describes the supported types,
+ e.g. linear, overlay. -->
+ <attr name="adServiceTypes" format="reference" />
+ </declare-styleable>
+
<!-- Attributes that can be used with <code>rating-system-definition</code> tags inside of the
XML resource that describes TV content rating of a {@link android.media.tv.TvInputService},
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bf8e55fd986f..d0de5f0e4104 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4255,6 +4255,9 @@
-->
<bool name="config_wallpaperTopApp">false</bool>
+ <!-- True if the device supports dVRR -->
+ <bool name="config_supportsDvrr">false</bool>
+
<!-- True if the device supports at least one form of multi-window.
E.g. freeform, split-screen, picture-in-picture. -->
<bool name="config_supportsMultiWindow">true</bool>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index f10e7f8c337e..540967d28d9b 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -117,6 +117,8 @@
<public name="isVirtualDeviceOnly"/>
<!-- @FlaggedApi("android.content.pm.sdk_lib_independence") -->
<public name="optional"/>
+ <!-- @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") -->
+ <public name="adServiceTypes" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01bc0000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fd6158d02b8f..ef272ee8bef1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -404,6 +404,7 @@
<java-symbol type="bool" name="config_supportAudioSourceUnprocessed" />
<java-symbol type="bool" name="config_freeformWindowManagement" />
<java-symbol type="bool" name="config_supportsBubble" />
+ <java-symbol type="bool" name="config_supportsDvrr" />
<java-symbol type="bool" name="config_supportsMultiWindow" />
<java-symbol type="bool" name="config_supportsSplitScreenMultiWindow" />
<java-symbol type="bool" name="config_supportsMultiDisplay" />
diff --git a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
index d629f6a8c57c..1925588e8904 100644
--- a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
+++ b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
@@ -166,6 +166,15 @@ public class AutomaticZenRuleTest {
@Test
@EnableFlags(Flags.FLAG_MODES_API)
+ public void builderConstructor_nullInputs_throws() {
+ assertThrows(NullPointerException.class,
+ () -> new AutomaticZenRule.Builder(null, Uri.parse("condition")));
+ assertThrows(NullPointerException.class,
+ () -> new AutomaticZenRule.Builder("name", null));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
public void validate_builderWithValidType_succeeds() throws Exception {
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
.setType(AutomaticZenRule.TYPE_BEDTIME)
diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
index 0c5e9664bbde..fc233fba082e 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -161,6 +161,18 @@ public class ArrayUtilsTest {
}
@Test
+ public void testAppendBoolean() throws Exception {
+ assertArrayEquals(new boolean[] { true },
+ ArrayUtils.appendBoolean(null, true));
+ assertArrayEquals(new boolean[] { true },
+ ArrayUtils.appendBoolean(new boolean[] { }, true));
+ assertArrayEquals(new boolean[] { true, false },
+ ArrayUtils.appendBoolean(new boolean[] { true }, false));
+ assertArrayEquals(new boolean[] { true, true },
+ ArrayUtils.appendBoolean(new boolean[] { true }, true));
+ }
+
+ @Test
public void testRemoveLong() throws Exception {
assertNull(ArrayUtils.removeLong(null, 1));
assertArrayEquals(new long[] { },
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index c98090638010..8d8dc10951a6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -49,6 +49,11 @@ public interface BackAnimation {
@BackEvent.SwipeEdge int swipeEdge);
/**
+ * Called when the input pointers are pilfered.
+ */
+ void onPilferPointers();
+
+ /**
* Sets whether the back gesture is past the trigger threshold or not.
*/
void setTriggerBack(boolean triggerBack);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index cf858dcb0637..d8c691b01b61 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -111,6 +111,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
/** Tracks if we should start the back gesture on the next motion move event */
private boolean mShouldStartOnNextMoveEvent = false;
+ private boolean mOnBackStartDispatched = false;
private final FlingAnimationUtils mFlingAnimationUtils;
@@ -304,6 +305,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
@Override
+ public void onPilferPointers() {
+ BackAnimationController.this.onPilferPointers();
+ }
+
+ @Override
public void setTriggerBack(boolean triggerBack) {
mShellExecutor.execute(() -> BackAnimationController.this.setTriggerBack(triggerBack));
}
@@ -384,6 +390,16 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
return null;
}
+ @VisibleForTesting
+ void onPilferPointers() {
+ mCurrentTracker.updateStartLocation();
+ // Dispatch onBackStarted, only to app callbacks.
+ // System callbacks will receive onBackStarted when the remote animation starts.
+ if (!shouldDispatchToAnimator()) {
+ tryDispatchOnBackStarted(mActiveCallback, mCurrentTracker.createStartEvent(null));
+ }
+ }
+
/**
* Called when a new motion event needs to be transferred to this
* {@link BackAnimationController}
@@ -483,12 +499,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mActiveCallback = mBackNavigationInfo.getOnBackInvokedCallback();
// App is handling back animation. Cancel system animation latency tracking.
cancelLatencyTracking();
- dispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
+ tryDispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
}
}
private void onMove() {
- if (!mBackGestureStarted || mBackNavigationInfo == null || mActiveCallback == null) {
+ if (!mBackGestureStarted
+ || mBackNavigationInfo == null
+ || mActiveCallback == null
+ || !mOnBackStartDispatched) {
return;
}
// Skip dispatching if the move corresponds to the queued instead of the current gesture
@@ -524,13 +543,14 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
&& mBackNavigationInfo.isPrepareRemoteAnimation();
}
- private void dispatchOnBackStarted(IOnBackInvokedCallback callback,
+ private void tryDispatchOnBackStarted(IOnBackInvokedCallback callback,
BackMotionEvent backEvent) {
- if (callback == null) {
+ if (callback == null || mOnBackStartDispatched) {
return;
}
try {
callback.onBackStarted(backEvent);
+ mOnBackStartDispatched = true;
} catch (RemoteException e) {
Log.e(TAG, "dispatchOnBackStarted error: ", e);
}
@@ -828,6 +848,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
void finishBackNavigation(boolean triggerBack) {
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishBackNavigation()");
mActiveCallback = null;
+ mShouldStartOnNextMoveEvent = false;
+ mOnBackStartDispatched = false;
mShellBackAnimationRegistry.resetDefaultCrossActivity();
cancelLatencyTracking();
if (mBackNavigationInfo != null) {
@@ -909,7 +931,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
::onBackAnimationFinished));
if (apps.length >= 1) {
- dispatchOnBackStarted(
+ mCurrentTracker.updateStartLocation();
+ tryDispatchOnBackStarted(
mActiveCallback,
mCurrentTracker.createStartEvent(apps[0]));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index 19eb928d4e30..4bd56d460818 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -104,6 +104,15 @@ class TouchTracker {
mStartThresholdX = mInitTouchX;
}
+ /** Update the start location used to compute the progress
+ * to the latest touch location.
+ */
+ void updateStartLocation() {
+ mInitTouchX = mLatestTouchX;
+ mInitTouchY = mLatestTouchY;
+ mStartThresholdX = mInitTouchX;
+ }
+
void reset() {
mInitTouchX = 0;
mInitTouchY = 0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index f5c01d063707..4c477373c32c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -769,7 +769,6 @@ public class PipAnimationController {
getSurfaceTransactionHelper().crop(tx, leash, destBounds);
}
if (mContentOverlay != null) {
- mContentOverlay.onAnimationEnd(tx, destBounds);
clearContentOverlay();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
index a2bd47c5285e..e11e8596a7fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
@@ -67,15 +67,6 @@ public abstract class PipContentOverlay {
public abstract void onAnimationUpdate(SurfaceControl.Transaction atomicTx,
Rect currentBounds, float fraction);
- /**
- * Callback when reaches the end of animation on the internal {@link #mLeash}.
- * @param atomicTx {@link SurfaceControl.Transaction} to operate, you should not explicitly
- * call apply on this transaction, it should be applied on the caller side.
- * @param destinationBounds {@link Rect} of the final bounds.
- */
- public abstract void onAnimationEnd(SurfaceControl.Transaction atomicTx,
- Rect destinationBounds);
-
/** A {@link PipContentOverlay} uses solid color. */
public static final class PipColorOverlay extends PipContentOverlay {
private static final String TAG = PipColorOverlay.class.getSimpleName();
@@ -107,11 +98,6 @@ public abstract class PipContentOverlay {
atomicTx.setAlpha(mLeash, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2);
}
- @Override
- public void onAnimationEnd(SurfaceControl.Transaction atomicTx, Rect destinationBounds) {
- // Do nothing. Color overlay should be fully opaque by now, ready for fade out.
- }
-
private float[] getContentOverlayColor(Context context) {
final TypedArray ta = context.obtainStyledAttributes(new int[] {
android.R.attr.colorBackground });
@@ -164,11 +150,6 @@ public abstract class PipContentOverlay {
Rect currentBounds, float fraction) {
// Do nothing. Keep the snapshot till animation ends.
}
-
- @Override
- public void onAnimationEnd(SurfaceControl.Transaction atomicTx, Rect destinationBounds) {
- // Do nothing. Snapshot overlay should be fully opaque by now, ready for fade out.
- }
}
/** A {@link PipContentOverlay} shows app icon on solid color background. */
@@ -255,11 +236,6 @@ public abstract class PipContentOverlay {
}
@Override
- public void onAnimationEnd(SurfaceControl.Transaction atomicTx, Rect destinationBounds) {
- // Do nothing. Icon overlay should be fully opaque by now, ready for fade out.
- }
-
- @Override
public void detach(SurfaceControl.Transaction tx) {
super.detach(tx);
if (mBitmap != null && !mBitmap.isRecycled()) {
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 743b1ea197bc..3635165d76ce 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
@@ -329,15 +329,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private @Surface.Rotation int mCurrentRotation;
/**
- * An optional overlay used to mask content changing between an app in/out of PiP, only set if
- * {@link PipTransitionState#getInSwipePipToHomeTransition()} is true, only in gesture nav.
- */
- @Nullable
- SurfaceControl mSwipePipToHomeOverlay;
-
- /**
- * An optional overlay used to mask content changing between an app in/out of PiP, only set if
- * {@link PipTransitionState#getInSwipePipToHomeTransition()} is false.
+ * An optional overlay used to mask content changing between an app in/out of PiP.
*/
@Nullable
SurfaceControl mPipOverlay;
@@ -480,7 +472,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return;
}
mPipBoundsState.setBounds(destinationBounds);
- mSwipePipToHomeOverlay = overlay;
+ mPipOverlay = overlay;
if (ENABLE_SHELL_TRANSITIONS && overlay != null) {
// With Shell transition, the overlay was attached to the remote transition leash, which
// will be removed when the current transition is finished, so we need to reparent it
@@ -892,7 +884,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
final Rect destinationBounds = mPipBoundsState.getBounds();
- final SurfaceControl swipeToHomeOverlay = mSwipePipToHomeOverlay;
+ final SurfaceControl swipeToHomeOverlay = mPipOverlay;
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
.resetScale(tx, mLeash, destinationBounds)
@@ -911,7 +903,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
}, tx);
mPipTransitionState.setInSwipePipToHomeTransition(false);
- mSwipePipToHomeOverlay = null;
+ mPipOverlay = null;
}
private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable,
@@ -1126,9 +1118,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
clearWaitForFixedRotation();
- if (mSwipePipToHomeOverlay != null) {
- removeContentOverlay(mSwipePipToHomeOverlay, null /* callback */);
- mSwipePipToHomeOverlay = null;
+ if (mPipOverlay != null) {
+ removeContentOverlay(mPipOverlay, null /* callback */);
+ mPipOverlay = null;
}
resetShadowRadius();
mPipTransitionState.setInSwipePipToHomeTransition(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 0f3c16220dee..f5f15d81ea44 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
@@ -465,7 +465,7 @@ public class PipTransition extends PipTransitionController {
mSurfaceTransactionHelper.crop(tx, leash, destinationBounds)
.resetScale(tx, leash, destinationBounds)
.round(tx, leash, true /* applyCornerRadius */);
- if (mPipOrganizer.mSwipePipToHomeOverlay != null && !mInitBounds.isEmpty()) {
+ if (mPipOrganizer.mPipOverlay != null && !mInitBounds.isEmpty()) {
// Resetting the scale for pinned task while re-adjusting its crop,
// also scales the overlay. So we need to update the overlay leash too.
Rect overlayBounds = new Rect(destinationBounds);
@@ -476,7 +476,7 @@ public class PipTransition extends PipTransitionController {
(destinationBounds.width() - overlaySize) / 2,
(destinationBounds.height() - overlaySize) / 2);
mSurfaceTransactionHelper.resetScale(tx,
- mPipOrganizer.mSwipePipToHomeOverlay, overlayBounds);
+ mPipOrganizer.mPipOverlay, overlayBounds);
}
}
mInitBounds.setEmpty();
@@ -615,9 +615,9 @@ public class PipTransition extends PipTransitionController {
}
}
// if overlay is present remove it immediately, as exit transition came before it faded out
- if (mPipOrganizer.mSwipePipToHomeOverlay != null) {
- startTransaction.remove(mPipOrganizer.mSwipePipToHomeOverlay);
- clearSwipePipToHomeOverlay();
+ if (mPipOrganizer.mPipOverlay != null) {
+ startTransaction.remove(mPipOrganizer.mPipOverlay);
+ clearPipOverlay();
}
if (pipChange == null) {
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
@@ -1077,7 +1077,7 @@ public class PipTransition extends PipTransitionController {
if (mFixedRotationState == FIXED_ROTATION_CALLBACK && appBounds != null) {
mInitBounds.set(appBounds);
}
- final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mSwipePipToHomeOverlay;
+ final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mPipOverlay;
if (swipePipToHomeOverlay != null) {
// Launcher fade in the overlay on top of the fullscreen Task. It is possible we
// reparent the PIP activity to a new PIP task (in case there are other activities
@@ -1106,7 +1106,7 @@ public class PipTransition extends PipTransitionController {
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
if (swipePipToHomeOverlay != null) {
mPipOrganizer.fadeOutAndRemoveOverlay(swipePipToHomeOverlay,
- this::clearSwipePipToHomeOverlay /* callback */, false /* withStartDelay */);
+ this::clearPipOverlay /* callback */, false /* withStartDelay */);
}
mPipTransitionState.setInSwipePipToHomeTransition(false);
}
@@ -1250,8 +1250,8 @@ public class PipTransition extends PipTransitionController {
mPipMenuController.updateMenuBounds(destinationBounds);
}
- private void clearSwipePipToHomeOverlay() {
- mPipOrganizer.mSwipePipToHomeOverlay = null;
+ private void clearPipOverlay() {
+ mPipOrganizer.mPipOverlay = null;
}
@Override
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 0367ba160605..d023cea6d19d 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
@@ -995,16 +995,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
t.show(mOpeningTasks.get(i).mTaskSurface);
}
for (int i = 0; i < mPausingTasks.size(); ++i) {
- if (!sendUserLeaveHint && mPausingTasks.get(i).isLeaf()) {
- // This means recents is not *actually* finishing, so of course we gotta
- // do special stuff in WMCore to accommodate.
- wct.setDoNotPip(mPausingTasks.get(i).mToken);
- }
- // Since we will reparent out of the leashes, pre-emptively hide the child
- // surface to match the leash. Otherwise, there will be a flicker before the
- // visibility gets committed in Core when using split-screen (in splitscreen,
- // the leaf-tasks are not "independent" so aren't hidden by normal setup).
- t.hide(mPausingTasks.get(i).mTaskSurface);
+ cleanUpPausingOrClosingTask(mPausingTasks.get(i), wct, t, sendUserLeaveHint);
+ }
+ for (int i = 0; i < mClosingTasks.size(); ++i) {
+ cleanUpPausingOrClosingTask(mClosingTasks.get(i), wct, t, sendUserLeaveHint);
}
if (mPipTransaction != null && sendUserLeaveHint) {
SurfaceControl pipLeash = null;
@@ -1053,6 +1047,20 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
}
}
+ private void cleanUpPausingOrClosingTask(TaskState task, WindowContainerTransaction wct,
+ SurfaceControl.Transaction finishTransaction, boolean sendUserLeaveHint) {
+ if (!sendUserLeaveHint && task.isLeaf()) {
+ // This means recents is not *actually* finishing, so of course we gotta
+ // do special stuff in WMCore to accommodate.
+ wct.setDoNotPip(task.mToken);
+ }
+ // Since we will reparent out of the leashes, pre-emptively hide the child
+ // surface to match the leash. Otherwise, there will be a flicker before the
+ // visibility gets committed in Core when using split-screen (in splitscreen,
+ // the leaf-tasks are not "independent" so aren't hidden by normal setup).
+ finishTransaction.hide(task.mTaskSurface);
+ }
+
@Override
public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
}
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 77427d999aaf..96e57e71f05c 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
@@ -223,6 +223,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private boolean mExitSplitScreenOnHide;
private boolean mIsDividerRemoteAnimating;
private boolean mIsDropEntering;
+ private boolean mSkipEvictingMainStageChildren;
private boolean mIsExiting;
private boolean mIsRootTranslucent;
@VisibleForTesting
@@ -468,6 +469,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
// Due to drag already pip task entering split by this method so need to reset flag here.
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
return true;
}
@@ -572,6 +574,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
+ // Don't evict the main stage children as this can race and happen after the activity is
+ // started into that stage
+ if (!isSplitScreenVisible()) {
+ mSkipEvictingMainStageChildren = true;
+ // Starting the split task without evicting children will bring the single root task
+ // container forward, so ensure that we hide the divider before we start animate it
+ setDividerVisibility(false, null);
+ }
+
// If split screen is not activated, we're expecting to open a pair of apps to split.
final int extraTransitType = mMainStage.isActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -600,6 +611,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
+ // Don't evict the main stage children as this can race and happen after the activity is
+ // started into that stage
+ if (!isSplitScreenVisible()) {
+ mSkipEvictingMainStageChildren = true;
+ // Starting the split task without evicting children will bring the single root task
+ // container forward, so ensure that we hide the divider before we start animate it
+ setDividerVisibility(false, null);
+ }
+
// If split screen is not activated, we're expecting to open a pair of apps to split.
final int extraTransitType = mMainStage.isActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -1618,7 +1638,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Ensure to evict old splitting tasks because the new split pair might be composed by
// one of the splitting tasks, evicting the task when finishing entering transition
// won't guarantee to put the task to the indicated new position.
- if (!mIsDropEntering) {
+ if (!mSkipEvictingMainStageChildren) {
mMainStage.evictAllChildren(wct);
}
mMainStage.reparentTopTask(wct);
@@ -1680,6 +1700,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
finishT.show(mRootTaskLeash);
setSplitsVisible(true);
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
mSplitRequest = null;
updateRecentTasksSplitPair();
if (!mLogger.hasStartedSession()) {
@@ -1929,6 +1950,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mIsDropEntering) {
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
} else {
mShowDecorImmediately = true;
mSplitLayout.flingDividerToCenter();
@@ -2123,6 +2145,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mIsDropEntering) {
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
} else {
mShowDecorImmediately = true;
mSplitLayout.flingDividerToCenter();
@@ -3245,6 +3268,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
public void onDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
if (!isSplitScreenVisible()) {
mIsDropEntering = true;
+ mSkipEvictingMainStageChildren = true;
}
if (!isSplitScreenVisible() && !ENABLE_SHELL_TRANSITIONS) {
// If split running background, exit split first.
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 e03f82526bdb..34c015f05c68 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
@@ -330,6 +330,11 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
continue;
}
if (isHide) {
+ if (pending.mType == TRANSIT_TO_BACK) {
+ // TO_BACK is only used when setting the task view visibility immediately,
+ // so in that case we can also hide the surface immediately
+ startTransaction.hide(chg.getLeash());
+ }
tv.prepareHideAnimation(finishTransaction);
} else {
tv.prepareCloseAnimation();
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 20ff79f7318e..98d343b66760 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
@@ -18,6 +18,7 @@ package com.android.wm.shell.unfold;
import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITIONS;
@@ -245,23 +246,29 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
public boolean shouldPlayUnfoldAnimation(@NonNull TransitionInfo transitionInfo) {
// Unfold animation won't play when animations are disabled
if (!ValueAnimator.areAnimatorsEnabled()) return false;
+ // Only handle transitions that are marked as physical display switch
+ // See PhysicalDisplaySwitchTransitionLauncher for the conditions
+ if ((transitionInfo.getFlags() & TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH) == 0) return false;
for (int i = 0; i < transitionInfo.getChanges().size(); i++) {
final TransitionInfo.Change change = transitionInfo.getChanges().get(i);
- if ((change.getFlags() & TransitionInfo.FLAG_IS_DISPLAY) != 0) {
- if (change.getEndAbsBounds() == null || change.getStartAbsBounds() == null) {
- continue;
- }
+ // We are interested only in display container changes
+ if ((change.getFlags() & TransitionInfo.FLAG_IS_DISPLAY) == 0) {
+ continue;
+ }
- // Handle only unfolding, currently we don't have an animation when folding
- final int afterArea =
- change.getEndAbsBounds().width() * change.getEndAbsBounds().height();
- final int beforeArea = change.getStartAbsBounds().width()
- * change.getStartAbsBounds().height();
+ // Handle only unfolding, currently we don't have an animation when folding
+ if (change.getEndAbsBounds() == null || change.getStartAbsBounds() == null) {
+ continue;
+ }
- if (afterArea > beforeArea) {
- return true;
- }
+ final int afterArea =
+ change.getEndAbsBounds().width() * change.getEndAbsBounds().height();
+ final int beforeArea = change.getStartAbsBounds().width()
+ * change.getStartAbsBounds().height();
+
+ if (afterArea > beforeArea) {
+ return true;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 0395a9b78b2b..771876f7ce5d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -182,8 +182,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
}
private void triggerBackGesture() {
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 0);
+ doStartEvents(0, 0);
mController.setTriggerBack(true);
}
@@ -244,10 +243,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
/* enableAnimation = */ true,
/* isAnimationCallback = */ false);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
- // Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
@@ -270,10 +266,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
/* enableAnimation = */ true,
/* isAnimationCallback = */ true);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
// Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100, 3000);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
@@ -359,8 +353,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
.injectInputEvent(any(KeyEvent.class), any(Integer.class));
// Verify that we start accepting gestures again once transition finishes.
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
@@ -399,8 +392,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
.injectInputEvent(any(KeyEvent.class), any(Integer.class));
// Verify that we start accepting gestures again once transition finishes.
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
@@ -427,8 +419,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
mShellExecutor.flushAll();
reset(mAnimatorCallback);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
}
@@ -441,9 +432,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
/* enableAnimation = */ true,
/* isAnimationCallback = */ false);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- // Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
@@ -563,10 +552,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
/* enableAnimation = */ true,
/* isAnimationCallback = */ false);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
// Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
@@ -593,6 +580,15 @@ public class BackAnimationControllerTest extends ShellTestCase {
/* swipeEdge */ BackEvent.EDGE_LEFT);
}
+ /**
+ * Simulate event sequence that starts a back navigation.
+ */
+ private void doStartEvents(int startX, int moveX) {
+ doMotionEvent(MotionEvent.ACTION_DOWN, startX);
+ mController.onPilferPointers();
+ doMotionEvent(MotionEvent.ACTION_MOVE, moveX);
+ }
+
private void simulateRemoteAnimationStart() throws RemoteException {
RemoteAnimationTarget animationTarget = createAnimationTarget();
RemoteAnimationTarget[] targets = new RemoteAnimationTarget[]{animationTarget};
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
index fc1fe1cd0acc..c5e229feaba7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
@@ -18,12 +18,11 @@ package com.android.wm.shell.unfold;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH;
import static android.view.WindowManager.TRANSIT_NONE;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -40,22 +39,17 @@ import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import com.android.window.flags.FakeFeatureFlagsImpl;
-import com.android.window.flags.FeatureFlags;
-import com.android.window.flags.Flags;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.TransitionInfoBuilder;
+import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.Transitions.TransitionFinishCallback;
import com.android.wm.shell.unfold.animation.FullscreenUnfoldTaskAnimator;
import com.android.wm.shell.unfold.animation.SplitTaskUnfoldAnimator;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.List;
@@ -196,6 +190,22 @@ public class UnfoldTransitionHandlerTest {
}
@Test
+ public void startAnimation_differentTransitionFromRequestWithResize_doesNotStartAnimation() {
+ mUnfoldTransitionHandler.handleRequest(new Binder(), createNoneTransitionInfo());
+ TransitionFinishCallback finishCallback = mock(TransitionFinishCallback.class);
+
+ boolean animationStarted = mUnfoldTransitionHandler.startAnimation(
+ mTransition,
+ createDisplayResizeTransitionInfo(),
+ mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class),
+ finishCallback
+ );
+
+ assertThat(animationStarted).isFalse();
+ }
+
+ @Test
public void startAnimation_differentTransitionFromRequestWithoutUnfold_doesNotStart() {
mUnfoldTransitionHandler.handleRequest(new Binder(), createNoneTransitionInfo());
TransitionFinishCallback finishCallback = mock(TransitionFinishCallback.class);
@@ -403,24 +413,18 @@ public class UnfoldTransitionHandlerTest {
}
}
- static class TestCase {
- private final boolean mShouldHandleMixedUnfold;
-
- public TestCase(boolean shouldHandleMixedUnfold) {
- mShouldHandleMixedUnfold = shouldHandleMixedUnfold;
- }
-
- public boolean mixedUnfoldFlagEnabled() {
- return mShouldHandleMixedUnfold;
- }
-
- @Override
- public String toString() {
- return "shouldHandleMixedUnfold flag = " + mShouldHandleMixedUnfold;
- }
+ private TransitionInfo createUnfoldTransitionInfo() {
+ TransitionInfo transitionInfo = new TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0);
+ TransitionInfo.Change change = new TransitionInfo.Change(null, mock(SurfaceControl.class));
+ change.setStartAbsBounds(new Rect(0, 0, 10, 10));
+ change.setEndAbsBounds(new Rect(0, 0, 100, 100));
+ change.setFlags(TransitionInfo.FLAG_IS_DISPLAY);
+ transitionInfo.addChange(change);
+ transitionInfo.setFlags(TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH);
+ return transitionInfo;
}
- private TransitionInfo createUnfoldTransitionInfo() {
+ private TransitionInfo createDisplayResizeTransitionInfo() {
TransitionInfo transitionInfo = new TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0);
TransitionInfo.Change change = new TransitionInfo.Change(null, mock(SurfaceControl.class));
change.setStartAbsBounds(new Rect(0, 0, 10, 10));
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 901ea46ba38b..a8ffd2b4dd8f 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -110,6 +110,10 @@ interface ITvInputManager {
void pauseRecording(in IBinder sessionToken, in Bundle params, int userId);
void resumeRecording(in IBinder sessionToken, in Bundle params, int userId);
+ // For playback control
+ void startPlayback(in IBinder sessionToken, int userId);
+ void stopPlayback(in IBinder sessionToken, int mode, int userId);
+
// For broadcast info
void requestBroadcastInfo(in IBinder sessionToken, in BroadcastInfoRequest request, int userId);
void removeBroadcastInfo(in IBinder sessionToken, int id, int userId);
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 5246f5c4dc1e..e37ee6e342e5 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -63,6 +63,9 @@ oneway interface ITvInputSession {
void timeShiftSetMode(int mode);
void timeShiftEnablePositionTracking(boolean enable);
+ void startPlayback();
+ void stopPlayback(int mode);
+
// For the recording session
void startRecording(in Uri programUri, in Bundle params);
void stopRecording();
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index d749b91e3889..ae3ee6535c71 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -79,6 +79,8 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
private static final int DO_TIME_SHIFT_SET_MODE = 30;
private static final int DO_SET_TV_MESSAGE_ENABLED = 31;
private static final int DO_NOTIFY_TV_MESSAGE = 32;
+ private static final int DO_STOP_PLAYBACK = 33;
+ private static final int DO_START_PLAYBACK = 34;
private final boolean mIsRecordingSession;
private final HandlerCaller mCaller;
@@ -286,6 +288,14 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
mTvInputSessionImpl.onTvMessageReceived((Integer) args.arg1, (Bundle) args.arg2);
break;
}
+ case DO_STOP_PLAYBACK: {
+ mTvInputSessionImpl.stopPlayback(msg.arg1);
+ break;
+ }
+ case DO_START_PLAYBACK: {
+ mTvInputSessionImpl.startPlayback();
+ break;
+ }
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
break;
@@ -483,6 +493,17 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
enabled));
}
+ @Override
+ public void stopPlayback(int mode) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_STOP_PLAYBACK, mode));
+ }
+
+ @Override
+ public void startPlayback() {
+ mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_START_PLAYBACK));
+ }
+
+
private final class TvInputEventReceiver extends InputEventReceiver {
TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 631ab9a2693d..c685a5adb08b 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -339,6 +339,14 @@ public final class TvInputManager {
*/
public static final int VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN = VIDEO_UNAVAILABLE_REASON_END;
+ /**
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
+ * it has been stopped by stopPlayback.
+ * @hide
+ */
+ public static final int VIDEO_UNAVAILABLE_REASON_STOPPED = 19;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
@@ -3302,6 +3310,30 @@ public final class TvInputManager {
}
}
+ void stopPlayback(int mode) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.stopPlayback(mToken, mode, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void startPlayback() {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.startPlayback(mToken, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Sends TV messages to the service for testing purposes
*/
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 720d9a6291de..55fa51755177 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -34,6 +34,7 @@ import android.graphics.Rect;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.AudioPresentation;
import android.media.PlaybackParams;
+import android.media.tv.interactive.TvInteractiveAppService;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
@@ -1531,6 +1532,32 @@ public abstract class TvInputService extends Service {
}
/**
+ * Called when the application requests playback of the Audio, Video, and CC streams to be
+ * stopped, but the metadata should continue to be filtered.
+ *
+ * <p>The metadata that will continue to be filtered includes the PSI
+ * (Program specific information) and SI (Service Information), part of ISO/IEC 13818-1.
+ *
+ * <p> Note that this is different form {@link #timeShiftPause()} as should release the
+ * stream, making it impossible to resume from this position again.
+ * @param mode
+ * @hide
+ */
+ public void onStopPlayback(@TvInteractiveAppService.PlaybackCommandStopMode int mode) {
+ }
+
+ /**
+ * Starts playback of the Audio, Video, and CC streams.
+ *
+ * <p> Note that this is different form {@link #timeShiftResume()} as this is intended to be
+ * used after stopping playback. This is used to restart playback from the current position
+ * in the live broadcast.
+ * @hide
+ */
+ public void onStartPlayback() {
+ }
+
+ /**
* Called when the application requests to play a given recorded TV program.
*
* @param recordedProgramUri The URI of a recorded TV program.
@@ -1993,6 +2020,20 @@ public abstract class TvInputService extends Service {
}
/**
+ * Calls {@link #onStopPlayback(int)}.
+ */
+ void stopPlayback(int mode) {
+ onStopPlayback(mode);
+ }
+
+ /**
+ * Calls {@link #onStartPlayback()}.
+ */
+ void startPlayback() {
+ onStartPlayback();
+ }
+
+ /**
* Calls {@link #onTimeShiftPlay(Uri)}.
*/
void timeShiftPlay(Uri recordedProgramUri) {
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 196b5c3112c0..233f96675543 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -37,6 +37,7 @@ import android.media.PlaybackParams;
import android.media.tv.TvInputManager.Session;
import android.media.tv.TvInputManager.Session.FinishedInputEventCallback;
import android.media.tv.TvInputManager.SessionCallback;
+import android.media.tv.interactive.TvInteractiveAppService;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -643,6 +644,35 @@ public class TvView extends ViewGroup {
}
}
+ /**
+ * Stops playback of the Audio, Video, and CC streams, but continue filtering the metadata.
+ *
+ * <p>The metadata that will continue to be filtered includes the PSI
+ * (Program specific information) and SI (Service Information), part of ISO/IEC 13818-1.
+ *
+ * <p> Note that this is different form {@link #timeShiftPause()} as this completely drops
+ * the stream, making it impossible to resume from this position again.
+ * @hide
+ */
+ public void stopPlayback(@TvInteractiveAppService.PlaybackCommandStopMode int mode) {
+ if (mSession != null) {
+ mSession.stopPlayback(mode);
+ }
+ }
+
+ /**
+ * Starts playback of the Audio, Video, and CC streams.
+ *
+ * <p> Note that this is different form {@link #timeShiftResume()} as this is intended to be
+ * used after stopping playback. This is used to restart playback from the current position
+ * in the live broadcast.
+ * @hide
+ */
+ public void startPlayback() {
+ if (mSession != null) {
+ mSession.startPlayback();
+ }
+ }
/**
* Sends TV messages to the session for testing purposes
diff --git a/media/java/android/media/tv/ad/TvAdService.java b/media/java/android/media/tv/ad/TvAdService.java
index 61101f07923c..6897a78647c2 100644
--- a/media/java/android/media/tv/ad/TvAdService.java
+++ b/media/java/android/media/tv/ad/TvAdService.java
@@ -28,6 +28,14 @@ public abstract class TvAdService extends Service {
private static final String TAG = "TvAdService";
/**
+ * Name under which a TvAdService component publishes information about itself. This meta-data
+ * must reference an XML resource containing an
+ * <code>&lt;{@link android.R.styleable#TvAdService tv-ad-service}&gt;</code> tag.
+ * @hide
+ */
+ public static final String SERVICE_META_DATA = "android.media.tv.ad.service";
+
+ /**
* Base class for derived classes to implement to provide a TV AD session.
*/
public abstract static class Session implements KeyEvent.Callback {
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 0abf285bd19c..66282dc209ed 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -527,6 +527,15 @@ public class CompanionDeviceActivity extends FragmentActivity implements
final Drawable profileIcon = getIcon(this, PROFILE_ICONS.get(deviceProfile));
+ // No need to show permission consent dialog if it is a isSkipPrompt(true)
+ // AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
+ if (mRequest.isSkipPrompt()) {
+ Log.d(TAG, "Skipping the permission consent dialog.");
+ mSingleDeviceSpinner.setVisibility(View.GONE);
+ onUserSelectedDevice(mSelectedDevice);
+ return;
+ }
+
updatePermissionUi();
mProfileIcon.setImageDrawable(profileIcon);
@@ -598,6 +607,14 @@ public class CompanionDeviceActivity extends FragmentActivity implements
Log.d(TAG, "onDeviceClicked(): " + mSelectedDevice.toShortString());
+ // No need to show permission consent dialog if it is a isSkipPrompt(true)
+ // AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
+ if (mRequest.isSkipPrompt()) {
+ Log.d(TAG, "Skipping the permission consent dialog.");
+ onUserSelectedDevice(mSelectedDevice);
+ return;
+ }
+
updatePermissionUi();
mSummary.setVisibility(View.VISIBLE);
@@ -615,14 +632,6 @@ public class CompanionDeviceActivity extends FragmentActivity implements
this, PROFILE_TITLES.get(deviceProfile), mAppLabel, remoteDeviceName);
final Spanned summary;
- // No need to show permission consent dialog if it is a isSkipPrompt(true)
- // AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
- if (mRequest.isSkipPrompt()) {
- mSingleDeviceSpinner.setVisibility(View.GONE);
- onUserSelectedDevice(mSelectedDevice);
- return;
- }
-
if (deviceProfile == null && mRequest.isSingleDevice()) {
summary = getHtmlFromResources(this, summaryResourceId, remoteDeviceName);
mConstraintList.setVisibility(View.GONE);
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
index f216abb66a64..66bd6f502274 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
@@ -28,7 +28,14 @@ import androidx.compose.material.icons.outlined.Shield
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
@@ -41,14 +48,14 @@ import com.android.settingslib.spa.gallery.R
import com.android.settingslib.spa.widget.card.CardButton
import com.android.settingslib.spa.widget.card.CardModel
import com.android.settingslib.spa.widget.card.SettingsCard
-import com.android.settingslib.spa.widget.card.SettingsCollapsibleCard
import com.android.settingslib.spa.widget.card.SettingsCardContent
+import com.android.settingslib.spa.widget.card.SettingsCollapsibleCard
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
object CardPageProvider : SettingsPageProvider {
- override val name = "CardPage"
+ override val name = "Card"
override fun getTitle(arguments: Bundle?) = TITLE
@@ -79,10 +86,13 @@ object CardPageProvider : SettingsPageProvider {
@Composable
private fun SettingsCardWithoutIcon() {
+ var isVisible by rememberSaveable { mutableStateOf(true) }
SettingsCard(
CardModel(
title = stringResource(R.string.sample_title),
text = stringResource(R.string.sample_text),
+ isVisible = { isVisible },
+ onDismiss = { isVisible = false },
buttons = listOf(
CardButton(text = "Action") {},
),
@@ -92,21 +102,23 @@ object CardPageProvider : SettingsPageProvider {
@Composable
fun SampleSettingsCollapsibleCard() {
- SettingsCollapsibleCard(
- title = "More alerts",
- imageVector = Icons.Outlined.Error,
- models = listOf(
+ val context = LocalContext.current
+ var isVisible0 by rememberSaveable { mutableStateOf(true) }
+ val cards = remember {
+ mutableStateListOf(
CardModel(
- title = stringResource(R.string.sample_title),
- text = stringResource(R.string.sample_text),
+ title = context.getString(R.string.sample_title),
+ text = context.getString(R.string.sample_text),
imageVector = Icons.Outlined.PowerOff,
+ isVisible = { isVisible0 },
+ onDismiss = { isVisible0 = false },
buttons = listOf(
CardButton(text = "Action") {},
)
),
CardModel(
- title = stringResource(R.string.sample_title),
- text = stringResource(R.string.sample_text),
+ title = context.getString(R.string.sample_title),
+ text = context.getString(R.string.sample_text),
imageVector = Icons.Outlined.Shield,
buttons = listOf(
CardButton(text = "Action") {},
@@ -114,6 +126,11 @@ object CardPageProvider : SettingsPageProvider {
)
)
)
+ }
+ SettingsCollapsibleCard(
+ title = "More alerts",
+ imageVector = Icons.Outlined.Error,
+ models = cards.toList()
)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
index c143390f269c..993cb4ac85e5 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
@@ -37,6 +37,7 @@ object SettingsDimension {
val itemPaddingAround = 8.dp
val itemDividerHeight = 32.dp
+ val iconSmall = 16.dp
val iconLarge = 48.dp
/** The size when app icon is displayed in list. */
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
index c113f4332fc3..b18a1bc01388 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
@@ -28,5 +28,14 @@ data class CardModel(
val title: String,
val text: String,
val imageVector: ImageVector? = null,
+ val isVisible: () -> Boolean = { true },
+
+ /**
+ * A dismiss button will be displayed if this is not null.
+ *
+ * And this callback will be called when user clicks the button.
+ */
+ val onDismiss: (() -> Unit)? = null,
+
val buttons: List<CardButton> = emptyList(),
)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
index 43792787c5aa..7eec8888f025 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
@@ -16,28 +16,35 @@
package com.android.settingslib.spa.widget.card
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.debug.UiModePreviews
import com.android.settingslib.spa.framework.theme.SettingsDimension
@@ -87,20 +94,31 @@ fun SettingsCard(model: CardModel) {
@Composable
internal fun SettingsCardImpl(model: CardModel) {
- SettingsCardContent {
- Column(
- modifier = Modifier.padding(SettingsDimension.itemPaddingStart),
- verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
- ) {
- CardIcon(model.imageVector)
- SettingsTitle(model.title)
- SettingsBody(model.text)
- Buttons(model.buttons)
+ AnimatedVisibility(visible = model.isVisible()) {
+ SettingsCardContent {
+ Column(
+ modifier = Modifier.padding(SettingsDimension.itemPaddingStart),
+ verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
+ ) {
+ CardHeader(model.imageVector, model.onDismiss)
+ SettingsTitle(model.title)
+ SettingsBody(model.text)
+ Buttons(model.buttons)
+ }
}
}
}
@Composable
+fun CardHeader(imageVector: ImageVector?, onDismiss: (() -> Unit)? = null) {
+ Row(Modifier.fillMaxWidth()) {
+ CardIcon(imageVector)
+ Spacer(modifier = Modifier.weight(1f))
+ DismissButton(onDismiss)
+ }
+}
+
+@Composable
private fun CardIcon(imageVector: ImageVector?) {
if (imageVector != null) {
Icon(
@@ -113,6 +131,28 @@ private fun CardIcon(imageVector: ImageVector?) {
}
@Composable
+private fun DismissButton(onDismiss: (() -> Unit)?) {
+ if (onDismiss == null) return
+ Surface(
+ shape = CircleShape,
+ color = MaterialTheme.colorScheme.secondaryContainer,
+ ) {
+ IconButton(
+ onClick = onDismiss,
+ modifier = Modifier.size(SettingsDimension.itemIconSize)
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.Close,
+ contentDescription = stringResource(
+ androidx.compose.material3.R.string.m3c_snackbar_dismiss
+ ),
+ modifier = Modifier.size(SettingsDimension.iconSmall),
+ )
+ }
+ }
+}
+
+@Composable
private fun Buttons(buttons: List<CardButton>) {
if (buttons.isNotEmpty()) {
Row(
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
index bf192a18679e..6e36490beac7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
@@ -58,7 +58,7 @@ fun SettingsCollapsibleCard(
var expanded by rememberSaveable { mutableStateOf(false) }
SettingsCard {
SettingsCardContent {
- Header(title, imageVector, models.size, expanded) { expanded = it }
+ Header(title, imageVector, models.count { it.isVisible() }, expanded) { expanded = it }
}
AnimatedVisibility(expanded) {
Column {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
index fd3ae49d93c8..beb9433cdbf0 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
@@ -16,10 +16,18 @@
package com.android.settingslib.spa.widget.card
+import android.content.Context
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.isNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
@@ -31,6 +39,8 @@ class SettingsCardTest {
@get:Rule
val composeTestRule = createComposeRule()
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
@Test
fun settingsCard_titleDisplayed() {
composeTestRule.setContent {
@@ -96,6 +106,27 @@ class SettingsCardTest {
assertThat(buttonClicked).isTrue()
}
+ @Test
+ fun settingsCard_dismiss() {
+ composeTestRule.setContent {
+ var isVisible by remember { mutableStateOf(true) }
+ SettingsCard(
+ CardModel(
+ title = TITLE,
+ text = "",
+ isVisible = { isVisible },
+ onDismiss = { isVisible = false },
+ )
+ )
+ }
+
+ composeTestRule.onNodeWithContentDescription(
+ context.getString(androidx.compose.material3.R.string.m3c_snackbar_dismiss)
+ ).performClick()
+
+ composeTestRule.onNodeWithText(TEXT).isNotDisplayed()
+ }
+
private companion object {
const val TITLE = "Title"
const val TEXT = "Text"
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
index efe1c701b1f6..aba9d7be1e91 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
@@ -16,12 +16,20 @@
package com.android.settingslib.spa.widget.card
+import android.content.Context
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Error
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.isNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
@@ -32,6 +40,8 @@ class SettingsCollapsibleCardTest {
@get:Rule
val composeTestRule = createComposeRule()
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
@Test
fun settingsCollapsibleCard_titleDisplayed() {
setContent()
@@ -62,8 +72,22 @@ class SettingsCollapsibleCardTest {
composeTestRule.onNodeWithText(CARD_TEXT).assertIsDisplayed()
}
+ @Test
+ fun settingsCollapsibleCard_dismiss() {
+ setContent()
+ composeTestRule.onNodeWithText(TITLE).performClick()
+
+ composeTestRule.onNodeWithContentDescription(
+ context.getString(androidx.compose.material3.R.string.m3c_snackbar_dismiss)
+ ).performClick()
+
+ composeTestRule.onNodeWithText(CARD_TEXT).isNotDisplayed()
+ composeTestRule.onNodeWithText("0").assertIsDisplayed()
+ }
+
private fun setContent() {
composeTestRule.setContent {
+ var isVisible by rememberSaveable { mutableStateOf(true) }
SettingsCollapsibleCard(
title = TITLE,
imageVector = Icons.Outlined.Error,
@@ -71,6 +95,8 @@ class SettingsCollapsibleCardTest {
CardModel(
title = "",
text = CARD_TEXT,
+ isVisible = { isVisible },
+ onDismiss = { isVisible = false },
)
),
)
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 02374462f093..c51a9a07332f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -294,32 +294,6 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
}
/**
- * Checks whether add user is disabled on the device
- *
- * @param context {@link Context} for the calling user.
- *
- *
- * @param userId User to check enforced admin status for.
- *
- * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
- * or {@code null} If adding user is not disabled.
- */
- public static EnforcedAdmin checkIfAddUserDisallowed(Context context, int userId) {
- final UserManager um = UserManager.get(context);
- if (!um.hasUserRestriction(UserManager.DISALLOW_ADD_USER, UserHandle.of(userId))) {
- // Restriction is not enforced.
- return null;
- }
- EnforcedAdmin enforcedAdmin = checkIfRestrictionEnforced(context,
- UserManager.DISALLOW_ADD_USER, userId);
- if (enforcedAdmin != null) {
- return enforcedAdmin;
- }
- return EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(
- UserManager.DISALLOW_ADD_USER);
- }
-
- /**
* Check if an application is suspended.
*
* @return EnforcedAdmin Object containing the enforced admin component and admin user details,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 2cb44ec39a23..49ac0f864ed7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -28,7 +28,9 @@ import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.bluetooth.BluetoothLeBroadcastSettings;
import android.bluetooth.BluetoothLeBroadcastSubgroup;
+import android.bluetooth.BluetoothLeBroadcastSubgroupSettings;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
import android.content.ContentResolver;
@@ -42,10 +44,13 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.settingslib.R;
+import com.google.common.collect.ImmutableList;
+
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
@@ -376,6 +381,77 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
(mBroadcastCode != null && mBroadcastCode.length > 0) ? mBroadcastCode : null);
}
+ /**
+ * Start the private Broadcast for personal audio sharing or qr code sharing.
+ *
+ * <p>The broadcast will use random string for both broadcast name and subgroup program info;
+ * The broadcast will use random string for broadcast code; The broadcast will only have one
+ * subgroup due to system limitation; The subgroup language will be null.
+ *
+ * <p>If the system started the LE Broadcast, then the system calls the corresponding callback
+ * {@link BluetoothLeBroadcast.Callback}.
+ */
+ public void startPrivateBroadcast(int quality) {
+ mNewAppSourceName = "Sharing audio";
+ if (mServiceBroadcast == null) {
+ Log.d(TAG, "The BluetoothLeBroadcast is null when starting the private broadcast.");
+ return;
+ }
+ if (mServiceBroadcast.getAllBroadcastMetadata().size()
+ >= mServiceBroadcast.getMaximumNumberOfBroadcasts()) {
+ Log.d(TAG, "Skip starting the broadcast due to number limit.");
+ return;
+ }
+ String programInfo = getProgramInfo();
+ if (DEBUG) {
+ Log.d(TAG, "startBroadcast: language = null ,programInfo = " + programInfo);
+ }
+ // Current broadcast framework only support one subgroup
+ BluetoothLeBroadcastSubgroupSettings subgroupSettings =
+ buildBroadcastSubgroupSettings(/* language= */ null, programInfo, quality);
+ BluetoothLeBroadcastSettings settings =
+ buildBroadcastSettings(
+ true, // TODO: set to false after framework fix
+ TextUtils.isEmpty(programInfo) ? null : programInfo,
+ (mBroadcastCode != null && mBroadcastCode.length > 0)
+ ? mBroadcastCode
+ : null,
+ ImmutableList.of(subgroupSettings));
+ mServiceBroadcast.startBroadcast(settings);
+ }
+
+ private BluetoothLeBroadcastSettings buildBroadcastSettings(
+ boolean isPublic,
+ @Nullable String broadcastName,
+ @Nullable byte[] broadcastCode,
+ List<BluetoothLeBroadcastSubgroupSettings> subgroupSettingsList) {
+ BluetoothLeBroadcastSettings.Builder builder =
+ new BluetoothLeBroadcastSettings.Builder()
+ .setPublicBroadcast(isPublic)
+ .setBroadcastName(broadcastName)
+ .setBroadcastCode(broadcastCode);
+ for (BluetoothLeBroadcastSubgroupSettings subgroupSettings : subgroupSettingsList) {
+ builder.addSubgroupSettings(subgroupSettings);
+ }
+ return builder.build();
+ }
+
+ private BluetoothLeBroadcastSubgroupSettings buildBroadcastSubgroupSettings(
+ @Nullable String language, @Nullable String programInfo, int quality) {
+ BluetoothLeAudioContentMetadata metadata =
+ new BluetoothLeAudioContentMetadata.Builder()
+ .setLanguage(language)
+ .setProgramInfo(programInfo)
+ .build();
+ // Current broadcast framework only support one subgroup, thus we still maintain the latest
+ // metadata to keep legacy UI working.
+ mBluetoothLeAudioContentMetadata = metadata;
+ return new BluetoothLeBroadcastSubgroupSettings.Builder()
+ .setPreferredQuality(quality)
+ .setContentMetadata(mBluetoothLeAudioContentMetadata)
+ .build();
+ }
+
public String getProgramInfo() {
return mProgramInfo;
}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a26b311b1f8f..facb244a5489 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -61,6 +61,13 @@ flag {
}
flag {
+ name: "refactor_get_current_user"
+ namespace: "systemui"
+ description: "KeyguardUpdateMonitor.getCurrentUser() was providing outdated results."
+ bug: "305984787"
+}
+
+flag {
name: "notification_throttle_hun"
namespace: "systemui"
description: "During notification avalanche, throttle HUNs showing in fast succession."
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
index e538e093e60f..2944bd9f9a8e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
@@ -174,8 +174,8 @@ private fun <T> computeValue(
lerp: (T, T, Float) -> T,
canOverflow: Boolean,
): T {
- val state = layoutImpl.state.transitionState
- if (state !is TransitionState.Transition || !layoutImpl.isTransitionReady(state)) {
+ val transition = layoutImpl.state.currentTransition
+ if (transition == null || !layoutImpl.isTransitionReady(transition)) {
return sharedValue.value
}
@@ -191,10 +191,11 @@ private fun <T> computeValue(
return value as Element.SharedValue<T>
}
- val fromValue = sceneValue(state.fromScene)
- val toValue = sceneValue(state.toScene)
+ val fromValue = sceneValue(transition.fromScene)
+ val toValue = sceneValue(transition.toScene)
return if (fromValue != null && toValue != null) {
- val progress = if (canOverflow) state.progress else state.progress.coerceIn(0f, 1f)
+ val progress =
+ if (canOverflow) transition.progress else transition.progress.coerceIn(0f, 1f)
lerp(fromValue.value, toValue.value, progress)
} else if (fromValue != null) {
fromValue.value
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index de69c37d4630..ba6d00e3b7f5 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -28,11 +28,11 @@ import kotlinx.coroutines.launch
* the currently running transition, if there is one.
*/
internal fun CoroutineScope.animateToScene(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
target: SceneKey,
) {
- val state = layoutImpl.state.transitionState
- if (state.currentScene == target) {
+ val transitionState = layoutState.transitionState
+ if (transitionState.currentScene == target) {
// This can happen in 3 different situations, for which there isn't anything else to do:
// 1. There is no ongoing transition and [target] is already the current scene.
// 2. The user is swiping to [target] from another scene and released their pointer such
@@ -44,44 +44,47 @@ internal fun CoroutineScope.animateToScene(
return
}
- when (state) {
- is TransitionState.Idle -> animate(layoutImpl, target)
+ when (transitionState) {
+ is TransitionState.Idle -> animate(layoutState, target)
is TransitionState.Transition -> {
// A transition is currently running: first check whether `transition.toScene` or
// `transition.fromScene` is the same as our target scene, in which case the transition
// can be accelerated or reversed to end up in the target state.
- if (state.toScene == target) {
+ if (transitionState.toScene == target) {
// The user is currently swiping to [target] but didn't release their pointer yet:
// animate the progress to `1`.
- check(state.fromScene == state.currentScene)
- val progress = state.progress
+ check(transitionState.fromScene == transitionState.currentScene)
+ val progress = transitionState.progress
if ((1f - progress).absoluteValue < ProgressVisibilityThreshold) {
- // The transition is already finished (progress ~= 1): no need to animate.
- layoutImpl.state.transitionState = TransitionState.Idle(state.currentScene)
+ // The transition is already finished (progress ~= 1): no need to animate. We
+ // finish the current transition early to make sure that the current state
+ // change is committed.
+ layoutState.finishTransition(transitionState, transitionState.currentScene)
} else {
// The transition is in progress: start the canned animation at the same
// progress as it was in.
// TODO(b/290184746): Also take the current velocity into account.
- animate(layoutImpl, target, startProgress = progress)
+ animate(layoutState, target, startProgress = progress)
}
return
}
- if (state.fromScene == target) {
+ if (transitionState.fromScene == target) {
// There is a transition from [target] to another scene: simply animate the same
// transition progress to `0`.
- check(state.toScene == state.currentScene)
- val progress = state.progress
+ check(transitionState.toScene == transitionState.currentScene)
+ val progress = transitionState.progress
if (progress.absoluteValue < ProgressVisibilityThreshold) {
- // The transition is at progress ~= 0: no need to animate.
- layoutImpl.state.transitionState = TransitionState.Idle(state.currentScene)
+ // The transition is at progress ~= 0: no need to animate.We finish the current
+ // transition early to make sure that the current state change is committed.
+ layoutState.finishTransition(transitionState, transitionState.currentScene)
} else {
// TODO(b/290184746): Also take the current velocity into account.
- animate(layoutImpl, target, startProgress = progress, reversed = true)
+ animate(layoutState, target, startProgress = progress, reversed = true)
}
return
@@ -89,27 +92,22 @@ internal fun CoroutineScope.animateToScene(
// Generic interruption; the current transition is neither from or to [target].
// TODO(b/290930950): Better handle interruptions here.
- animate(layoutImpl, target)
+ animate(layoutState, target)
}
}
}
private fun CoroutineScope.animate(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
target: SceneKey,
startProgress: Float = 0f,
reversed: Boolean = false,
) {
- val fromScene = layoutImpl.state.transitionState.currentScene
+ val fromScene = layoutState.transitionState.currentScene
val isUserInput =
- (layoutImpl.state.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
+ (layoutState.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
?: false
- val animationSpec = layoutImpl.transitions.transitionSpec(fromScene, target).spec
- val visibilityThreshold =
- (animationSpec as? SpringSpec)?.visibilityThreshold ?: ProgressVisibilityThreshold
- val animatable = Animatable(startProgress, visibilityThreshold = visibilityThreshold)
-
val targetProgress = if (reversed) 0f else 1f
val transition =
if (reversed) {
@@ -119,7 +117,6 @@ private fun CoroutineScope.animate(
currentScene = target,
isInitiatedByUserInput = isUserInput,
isUserInputOngoing = false,
- animatable = animatable,
)
} else {
OneOffTransition(
@@ -128,21 +125,27 @@ private fun CoroutineScope.animate(
currentScene = target,
isInitiatedByUserInput = isUserInput,
isUserInputOngoing = false,
- animatable = animatable,
)
}
- // Change the current layout state to use this new transition.
- layoutImpl.state.transitionState = transition
+ // Change the current layout state to start this new transition. This will compute the
+ // TransformationSpec associated to this transition, which we need to initialize the Animatable
+ // that will actually animate it.
+ layoutState.startTransition(transition)
+
+ // The transformation now contains the spec that we should use to instantiate the Animatable.
+ val animationSpec = layoutState.transformationSpec.progressSpec
+ val visibilityThreshold =
+ (animationSpec as? SpringSpec)?.visibilityThreshold ?: ProgressVisibilityThreshold
+ val animatable =
+ Animatable(startProgress, visibilityThreshold = visibilityThreshold).also {
+ transition.animatable = it
+ }
// Animate the progress to its target value.
launch {
animatable.animateTo(targetProgress, animationSpec)
-
- // Unless some other external state change happened, the state should now be idle.
- if (layoutImpl.state.transitionState == transition) {
- layoutImpl.state.transitionState = TransitionState.Idle(target)
- }
+ layoutState.finishTransition(transition, target)
}
}
@@ -152,8 +155,16 @@ private class OneOffTransition(
override val currentScene: SceneKey,
override val isInitiatedByUserInput: Boolean,
override val isUserInputOngoing: Boolean,
- private val animatable: Animatable<Float, AnimationVector1D>,
) : TransitionState.Transition(fromScene, toScene) {
+ /**
+ * The animatable used to animate this transition.
+ *
+ * Note: This is lateinit because we need to first create this Transition object so that
+ * [SceneTransitionLayoutState] can compute the transformations and animation spec associated to
+ * it, which is need to initialize this Animatable.
+ */
+ lateinit var animatable: Animatable<Float, AnimationVector1D>
+
override val progress: Float
get() = animatable.value
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 431a8aef6d3d..5dc1079e8b56 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -181,15 +181,11 @@ private data class ElementModifier(
}
internal class ElementNode(
- layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
- element: Element,
- sceneValues: Element.TargetValues,
+ private var layoutImpl: SceneTransitionLayoutImpl,
+ private var scene: Scene,
+ private var element: Element,
+ private var sceneValues: Element.TargetValues,
) : Modifier.Node(), DrawModifierNode {
- private var layoutImpl: SceneTransitionLayoutImpl = layoutImpl
- private var scene: Scene = scene
- private var element: Element = element
- private var sceneValues: Element.TargetValues = sceneValues
override fun onAttach() {
super.onAttach()
@@ -283,26 +279,27 @@ private fun shouldDrawElement(
scene: Scene,
element: Element,
): Boolean {
- val state = layoutImpl.state.transitionState
+ val transition = layoutImpl.state.currentTransition
// Always draw the element if there is no ongoing transition or if the element is not shared.
if (
- state !is TransitionState.Transition ||
- !layoutImpl.isTransitionReady(state) ||
- state.fromScene !in element.sceneValues ||
- state.toScene !in element.sceneValues
+ transition == null ||
+ !layoutImpl.isTransitionReady(transition) ||
+ transition.fromScene !in element.sceneValues ||
+ transition.toScene !in element.sceneValues
) {
return true
}
- val sharedTransformation = sharedElementTransformation(layoutImpl, state, element.key)
+ val sharedTransformation =
+ sharedElementTransformation(layoutImpl.state, transition, element.key)
if (sharedTransformation?.enabled == false) {
return true
}
return shouldDrawOrComposeSharedElement(
layoutImpl,
- state,
+ transition,
scene.key,
element.key,
sharedTransformation,
@@ -331,21 +328,21 @@ internal fun shouldDrawOrComposeSharedElement(
}
private fun isSharedElementEnabled(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
transition: TransitionState.Transition,
element: ElementKey,
): Boolean {
- return sharedElementTransformation(layoutImpl, transition, element)?.enabled ?: true
+ return sharedElementTransformation(layoutState, transition, element)?.enabled ?: true
}
internal fun sharedElementTransformation(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
transition: TransitionState.Transition,
element: ElementKey,
): SharedElementTransformation? {
- val spec = layoutImpl.transitions.transitionSpec(transition.fromScene, transition.toScene)
- val sharedInFromScene = spec.transformations(element, transition.fromScene).shared
- val sharedInToScene = spec.transformations(element, transition.toScene).shared
+ val transformationSpec = layoutState.transformationSpec
+ val sharedInFromScene = transformationSpec.transformations(element, transition.fromScene).shared
+ val sharedInToScene = transformationSpec.transformations(element, transition.toScene).shared
// The sharedElement() transformation must either be null or be the same in both scenes.
if (sharedInFromScene != sharedInToScene) {
@@ -371,13 +368,9 @@ private fun isElementOpaque(
scene: Scene,
sceneValues: Element.TargetValues,
): Boolean {
- val state = layoutImpl.state.transitionState
-
- if (state !is TransitionState.Transition) {
- return true
- }
+ val transition = layoutImpl.state.currentTransition ?: return true
- if (!layoutImpl.isTransitionReady(state)) {
+ if (!layoutImpl.isTransitionReady(transition)) {
val lastValue =
sceneValues.lastValues.alpha.takeIf { it != Element.AlphaUnspecified }
?: element.lastSharedValues.alpha.takeIf { it != Element.AlphaUnspecified } ?: 1f
@@ -385,8 +378,8 @@ private fun isElementOpaque(
return lastValue == 1f
}
- val fromScene = state.fromScene
- val toScene = state.toScene
+ val fromScene = transition.fromScene
+ val toScene = transition.toScene
val fromValues = element.sceneValues[fromScene]
val toValues = element.sceneValues[toScene]
@@ -395,14 +388,11 @@ private fun isElementOpaque(
}
val isSharedElement = fromValues != null && toValues != null
- if (isSharedElement && isSharedElementEnabled(layoutImpl, state, element.key)) {
+ if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) {
return true
}
- return layoutImpl.transitions
- .transitionSpec(fromScene, toScene)
- .transformations(element.key, scene.key)
- .alpha == null
+ return layoutImpl.state.transformationSpec.transformations(element.key, scene.key).alpha == null
}
/**
@@ -607,24 +597,22 @@ private inline fun <T> computeValue(
lastValue: () -> T,
lerp: (T, T, Float) -> T,
): T {
- val state = layoutImpl.state.transitionState
-
- // There is no ongoing transition.
- if (state !is TransitionState.Transition) {
- // Even if this element SceneTransitionLayout is not animated, the layout itself might be
- // animated (e.g. by another parent SceneTransitionLayout), in which case this element still
- // need to participate in the layout phase.
- return currentValue()
- }
+ val transition =
+ layoutImpl.state.currentTransition
+ // There is no ongoing transition. Even if this element SceneTransitionLayout is not
+ // animated, the layout itself might be animated (e.g. by another parent
+ // SceneTransitionLayout), in which case this element still need to participate in the
+ // layout phase.
+ ?: return currentValue()
// A transition was started but it's not ready yet (not all elements have been composed/laid
// out yet). Use the last value that was set, to make sure elements don't unexpectedly jump.
- if (!layoutImpl.isTransitionReady(state)) {
+ if (!layoutImpl.isTransitionReady(transition)) {
return lastValue()
}
- val fromScene = state.fromScene
- val toScene = state.toScene
+ val fromScene = transition.fromScene
+ val toScene = transition.toScene
val fromValues = element.sceneValues[fromScene]
val toValues = element.sceneValues[toScene]
@@ -638,21 +626,17 @@ private inline fun <T> computeValue(
// TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared
// elements follow the finger direction.
val isSharedElement = fromValues != null && toValues != null
- if (isSharedElement && isSharedElementEnabled(layoutImpl, state, element.key)) {
+ if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) {
val start = sceneValue(fromValues!!)
val end = sceneValue(toValues!!)
// Make sure we don't read progress if values are the same and we don't need to interpolate,
// so we don't invalidate the phase where this is read.
- return if (start == end) start else lerp(start, end, state.progress)
+ return if (start == end) start else lerp(start, end, transition.progress)
}
val transformation =
- transformation(
- layoutImpl.transitions
- .transitionSpec(fromScene, toScene)
- .transformations(element.key, scene.key)
- )
+ transformation(layoutImpl.state.transformationSpec.transformations(element.key, scene.key))
// If there is no transformation explicitly associated to this element value, let's use
// the value given by the system (like the current position and size given by the layout
// pass).
@@ -675,7 +659,7 @@ private inline fun <T> computeValue(
scene,
element,
sceneValues,
- state,
+ transition,
idleValue,
)
@@ -685,7 +669,7 @@ private inline fun <T> computeValue(
return targetValue
}
- val progress = state.progress
+ val progress = transition.progress
// TODO(b/290184746): Make sure that we don't overflow transformations associated to a range.
val rangeProgress = transformation.range?.progress(progress) ?: progress
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
index 7029da2edb0d..306f27626e19 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
@@ -120,17 +120,13 @@ private fun shouldComposeMovableElement(
scene: SceneKey,
element: Element,
): Boolean {
- val transitionState = layoutImpl.state.transitionState
-
- // If we are idle, there is only one [scene] that is composed so we can compose our movable
- // content here.
- if (transitionState is TransitionState.Idle) {
- check(transitionState.currentScene == scene)
- return true
- }
-
- val fromScene = (transitionState as TransitionState.Transition).fromScene
- val toScene = transitionState.toScene
+ val transition =
+ layoutImpl.state.currentTransition
+ // If we are idle, there is only one [scene] that is composed so we can compose our
+ // movable content here.
+ ?: return true
+ val fromScene = transition.fromScene
+ val toScene = transition.toScene
val fromReady = layoutImpl.isSceneReady(fromScene)
val toReady = layoutImpl.isSceneReady(toScene)
@@ -181,10 +177,10 @@ private fun shouldComposeMovableElement(
return shouldDrawOrComposeSharedElement(
layoutImpl,
- transitionState,
+ transition,
scene,
element.key,
- sharedElementTransformation(layoutImpl, transitionState, element.key),
+ sharedElementTransformation(layoutImpl.state, transition, element.key),
)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index 32025b4f1258..e78f3266d664 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -179,7 +179,8 @@ private fun scenePriorityNestedScrollConnection(
bottomOrRightBehavior: NestedScrollBehavior,
) =
SceneNestedScrollHandler(
- gestureHandler = layoutImpl.gestureHandler(orientation = orientation),
+ layoutImpl = layoutImpl,
+ orientation = orientation,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
index 91decf4d8b7e..338557d0942e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -41,14 +41,9 @@ internal class SceneGestureHandler(
internal val orientation: Orientation,
private val coroutineScope: CoroutineScope,
) {
+ private val layoutState = layoutImpl.state
val draggable: DraggableHandler = SceneDraggableHandler(this)
- internal var transitionState
- get() = layoutImpl.state.transitionState
- set(value) {
- layoutImpl.state.transitionState = value
- }
-
private var _swipeTransition: SwipeTransition? = null
internal var swipeTransition: SwipeTransition
get() = _swipeTransition ?: error("SwipeTransition needs to be initialized")
@@ -57,27 +52,26 @@ internal class SceneGestureHandler(
}
private fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
- if (isDrivingTransition || force) transitionState = newTransition
+ if (isDrivingTransition || force) layoutState.startTransition(newTransition)
swipeTransition = newTransition
}
- internal val currentScene: Scene
- get() = layoutImpl.scene(transitionState.currentScene)
-
internal val isDrivingTransition
- get() = transitionState == _swipeTransition
+ get() = layoutState.transitionState == _swipeTransition
/**
* The velocity threshold at which the intent of the user is to swipe up or down. It is the same
* as SwipeableV2Defaults.VelocityThreshold.
*/
- internal val velocityThreshold = with(layoutImpl.density) { 125.dp.toPx() }
+ internal val velocityThreshold: Float
+ get() = with(layoutImpl.density) { 125.dp.toPx() }
/**
* The positional threshold at which the intent of the user is to swipe to the next scene. It is
* the same as SwipeableV2Defaults.PositionalThreshold.
*/
- private val positionalThreshold = with(layoutImpl.density) { 56.dp.toPx() }
+ private val positionalThreshold
+ get() = with(layoutImpl.density) { 56.dp.toPx() }
internal var gestureWithPriority: Any? = null
@@ -98,18 +92,18 @@ internal class SceneGestureHandler(
return
}
- val transition = transitionState
- if (transition is TransitionState.Transition) {
+ val transitionState = layoutState.transitionState
+ if (transitionState is TransitionState.Transition) {
// TODO(b/290184746): Better handle interruptions here if state != idle.
Log.w(
TAG,
"start from TransitionState.Transition is not fully supported: from" +
- " ${transition.fromScene} to ${transition.toScene} " +
- "(progress ${transition.progress})"
+ " ${transitionState.fromScene} to ${transitionState.toScene} " +
+ "(progress ${transitionState.progress})"
)
}
- val fromScene = currentScene
+ val fromScene = layoutImpl.scene(transitionState.currentScene)
setCurrentActions(fromScene, startedPosition, pointersDown)
val (targetScene, distance) =
@@ -364,7 +358,7 @@ internal class SceneGestureHandler(
findTargetSceneAndDistanceStrict(fromScene, velocity)
?: run {
// We will not animate
- transitionState = TransitionState.Idle(fromScene.key)
+ layoutState.finishTransition(swipeTransition, idleScene = fromScene.key)
return
}
@@ -439,14 +433,7 @@ internal class SceneGestureHandler(
)
swipeTransition.finishOffsetAnimation()
-
- // Now that the animation is done, the state should be idle. Note that if the state
- // was changed since this animation started, some external code changed it and we
- // shouldn't do anything here. Note also that this job will be cancelled in the case
- // where the user intercepts this swipe.
- if (isDrivingTransition) {
- transitionState = TransitionState.Idle(targetScene)
- }
+ layoutState.finishTransition(swipeTransition, targetScene)
}
}
}
@@ -539,10 +526,14 @@ private class SceneDraggableHandler(
}
internal class SceneNestedScrollHandler(
- private val gestureHandler: SceneGestureHandler,
+ private val layoutImpl: SceneTransitionLayoutImpl,
+ private val orientation: Orientation,
private val topOrLeftBehavior: NestedScrollBehavior,
private val bottomOrRightBehavior: NestedScrollBehavior,
) : NestedScrollHandler {
+ private val layoutState = layoutImpl.state
+ private val gestureHandler = layoutImpl.gestureHandler(orientation)
+
override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
private fun nestedScrollConnection(): PriorityNestedScrollConnection {
@@ -553,7 +544,7 @@ internal class SceneNestedScrollHandler(
val actionUpOrLeft =
Swipe(
direction =
- when (gestureHandler.orientation) {
+ when (orientation) {
Orientation.Horizontal -> SwipeDirection.Left
Orientation.Vertical -> SwipeDirection.Up
},
@@ -563,7 +554,7 @@ internal class SceneNestedScrollHandler(
val actionDownOrRight =
Swipe(
direction =
- when (gestureHandler.orientation) {
+ when (orientation) {
Orientation.Horizontal -> SwipeDirection.Right
Orientation.Vertical -> SwipeDirection.Down
},
@@ -571,7 +562,7 @@ internal class SceneNestedScrollHandler(
)
fun hasNextScene(amount: Float): Boolean {
- val fromScene = gestureHandler.currentScene
+ val fromScene = layoutImpl.scene(layoutState.transitionState.currentScene)
val nextScene =
when {
amount < 0f -> fromScene.userActions[actionUpOrLeft]
@@ -582,7 +573,7 @@ internal class SceneNestedScrollHandler(
}
return PriorityNestedScrollConnection(
- orientation = gestureHandler.orientation,
+ orientation = orientation,
canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
canChangeScene = offsetBeforeStart == 0f
@@ -590,8 +581,9 @@ internal class SceneNestedScrollHandler(
canChangeScene && gestureHandler.isDrivingTransition && offsetAvailable != 0f
if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false
- val progress = gestureHandler.swipeTransition.progress
- val threshold = gestureHandler.layoutImpl.transitionInterceptionThreshold
+ val swipeTransition = gestureHandler.swipeTransition
+ val progress = swipeTransition.progress
+ val threshold = layoutImpl.transitionInterceptionThreshold
fun isProgressCloseTo(value: Float) = (progress - value).absoluteValue <= threshold
// The transition is always between 0 and 1. If it is close to either of these
@@ -599,9 +591,8 @@ internal class SceneNestedScrollHandler(
// The progress value can go beyond this range in the case of overscroll.
val shouldSnapToIdle = isProgressCloseTo(0f) || isProgressCloseTo(1f)
if (shouldSnapToIdle) {
- gestureHandler.swipeTransition.cancelOffsetAnimation()
- gestureHandler.transitionState =
- TransitionState.Idle(gestureHandler.swipeTransition.currentScene)
+ swipeTransition.cancelOffsetAnimation()
+ layoutState.finishTransition(swipeTransition, swipeTransition.currentScene)
}
// Start only if we cannot consume this event
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 239971ff6be8..3608e374fdbc 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -19,6 +19,8 @@ package com.android.compose.animation.scene
import androidx.annotation.FloatRange
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
@@ -27,6 +29,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.platform.LocalDensity
+import kotlinx.coroutines.channels.Channel
/**
* [SceneTransitionLayout] is a container that automatically animates its content whenever
@@ -266,24 +269,45 @@ internal fun SceneTransitionLayoutForTesting(
val coroutineScope = rememberCoroutineScope()
val layoutImpl = remember {
SceneTransitionLayoutImpl(
+ state = state as SceneTransitionLayoutStateImpl,
onChangeScene = onChangeScene,
- builder = scenes,
- transitions = transitions,
- state = state,
density = density,
edgeDetector = edgeDetector,
transitionInterceptionThreshold = transitionInterceptionThreshold,
+ builder = scenes,
coroutineScope = coroutineScope,
)
.also { onLayoutImpl?.invoke(it) }
}
- layoutImpl.onChangeScene = onChangeScene
- layoutImpl.transitions = transitions
- layoutImpl.density = density
- layoutImpl.edgeDetector = edgeDetector
+ val targetSceneChannel = remember { Channel<SceneKey>(Channel.CONFLATED) }
+ SideEffect {
+ if (state != layoutImpl.state) {
+ error(
+ "This SceneTransitionLayout was bound to a different SceneTransitionLayoutState" +
+ " that was used when creating it, which is not supported"
+ )
+ }
+
+ layoutImpl.onChangeScene = onChangeScene
+ (state as SceneTransitionLayoutStateImpl).transitions = transitions
+ layoutImpl.density = density
+ layoutImpl.edgeDetector = edgeDetector
+ layoutImpl.updateScenes(scenes)
+
+ state.transitions = transitions
+
+ targetSceneChannel.trySend(currentScene)
+ }
+
+ LaunchedEffect(targetSceneChannel) {
+ for (newKey in targetSceneChannel) {
+ // Inspired by AnimateAsState.kt: let's poll the last value to avoid being one frame
+ // late.
+ val newKey = targetSceneChannel.tryReceive().getOrNull() ?: newKey
+ animateToScene(layoutImpl.state, newKey)
+ }
+ }
- layoutImpl.setScenes(scenes)
- layoutImpl.setCurrentScene(currentScene)
layoutImpl.Content(modifier)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index 00e33e24c41e..c99c3250bbb1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -22,13 +22,8 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -40,36 +35,40 @@ import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
import com.android.compose.ui.util.lerp
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.channels.Channel
@Stable
internal class SceneTransitionLayoutImpl(
- onChangeScene: (SceneKey) -> Unit,
+ internal val state: SceneTransitionLayoutStateImpl,
+ internal var onChangeScene: (SceneKey) -> Unit,
+ internal var density: Density,
+ internal var edgeDetector: EdgeDetector,
+ internal var transitionInterceptionThreshold: Float,
builder: SceneTransitionLayoutScope.() -> Unit,
- transitions: SceneTransitions,
- internal val state: SceneTransitionLayoutState,
- density: Density,
- edgeDetector: EdgeDetector,
- transitionInterceptionThreshold: Float,
coroutineScope: CoroutineScope,
) {
- internal val scenes = SnapshotStateMap<SceneKey, Scene>()
+ internal val scenes = mutableMapOf<SceneKey, Scene>()
+
+ /**
+ * The map of [Element]s.
+ *
+ * Note that this map is *mutated* directly during composition, so it is a [SnapshotStateMap] to
+ * make sure that mutations are reverted if composition is cancelled.
+ */
internal val elements = SnapshotStateMap<ElementKey, Element>()
- /** The scenes that are "ready", i.e. they were composed and fully laid-out at least once. */
+ /**
+ * The scenes that are "ready", i.e. they were composed and fully laid-out at least once.
+ *
+ * Note that this map is *read* during composition, so it is a [SnapshotStateMap] to make sure
+ * that we recompose when modifications are made to this map.
+ */
private val readyScenes = SnapshotStateMap<SceneKey, Boolean>()
- internal var onChangeScene by mutableStateOf(onChangeScene)
- internal var transitions by mutableStateOf(transitions)
- internal var density: Density by mutableStateOf(density)
- internal var edgeDetector by mutableStateOf(edgeDetector)
- internal var transitionInterceptionThreshold by mutableStateOf(transitionInterceptionThreshold)
-
private val horizontalGestureHandler: SceneGestureHandler
private val verticalGestureHandler: SceneGestureHandler
init {
- setScenes(builder)
+ updateScenes(builder)
// SceneGestureHandler must wait for the scenes to be initialized, in order to access the
// current scene (required for SwipeTransition).
@@ -98,7 +97,7 @@ internal class SceneTransitionLayoutImpl(
return scenes[key] ?: error("Scene $key is not configured")
}
- internal fun setScenes(builder: SceneTransitionLayoutScope.() -> Unit) {
+ internal fun updateScenes(builder: SceneTransitionLayoutScope.() -> Unit) {
// Keep a reference of the current scenes. After processing [builder], the scenes that were
// not configured will be removed.
val scenesToRemove = scenes.keys.toMutableSet()
@@ -141,20 +140,6 @@ internal class SceneTransitionLayoutImpl(
}
@Composable
- internal fun setCurrentScene(key: SceneKey) {
- val channel = remember { Channel<SceneKey>(Channel.CONFLATED) }
- SideEffect { channel.trySend(key) }
- LaunchedEffect(channel) {
- for (newKey in channel) {
- // Inspired by AnimateAsState.kt: let's poll the last value to avoid being one frame
- // late.
- val newKey = channel.tryReceive().getOrNull() ?: newKey
- animateToScene(this@SceneTransitionLayoutImpl, newKey)
- }
- }
- }
-
- @Composable
@OptIn(ExperimentalComposeUiApi::class)
internal fun Content(modifier: Modifier) {
Box(
@@ -171,14 +156,14 @@ internal class SceneTransitionLayoutImpl(
val width: Int
val height: Int
- val state = state.transitionState
- if (state !is TransitionState.Transition) {
+ val transition = state.currentTransition
+ if (transition == null) {
width = placeable.width
height = placeable.height
} else {
// Interpolate the size.
- val fromSize = scene(state.fromScene).targetSize
- val toSize = scene(state.toScene).targetSize
+ val fromSize = scene(transition.fromScene).targetSize
+ val toSize = scene(transition.toScene).targetSize
// Optimization: make sure we don't read state.progress if fromSize ==
// toSize to avoid running this code every frame when the layout size does
@@ -187,7 +172,7 @@ internal class SceneTransitionLayoutImpl(
width = fromSize.width
height = fromSize.height
} else {
- val size = lerp(fromSize, toSize, state.progress)
+ val size = lerp(fromSize, toSize, transition.progress)
width = size.width.coerceAtLeast(0)
height = size.height.coerceAtLeast(0)
}
@@ -228,13 +213,12 @@ internal class SceneTransitionLayoutImpl(
scene.Content(
Modifier.drawWithContent {
- when (val state = state.transitionState) {
- is TransitionState.Idle -> drawContent()
- is TransitionState.Transition -> {
- // Don't draw scenes that are not ready yet.
- if (readyScenes.containsKey(key)) {
- drawContent()
- }
+ if (state.currentTransition == null) {
+ drawContent()
+ } else {
+ // Don't draw scenes that are not ready yet.
+ if (readyScenes.containsKey(key)) {
+ drawContent()
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 623725582a9d..d1ba582d6c23 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -23,31 +23,32 @@ import androidx.compose.runtime.setValue
/** The state of a [SceneTransitionLayout]. */
@Stable
-class SceneTransitionLayoutState(initialScene: SceneKey) {
+sealed interface SceneTransitionLayoutState {
/**
* The current [TransitionState]. All values read here are backed by the Snapshot system.
*
* To observe those values outside of Compose/the Snapshot system, use
* [SceneTransitionLayoutState.observableTransitionState] instead.
*/
- var transitionState: TransitionState by mutableStateOf(TransitionState.Idle(initialScene))
+ val transitionState: TransitionState
+
+ /** The current transition, or `null` if we are idle. */
+ val currentTransition: TransitionState.Transition?
+ get() = transitionState as? TransitionState.Transition
/**
- * Whether we are transitioning, optionally restricting the check to the transition between
- * [from] and [to].
+ * Whether we are transitioning. If [from] or [to] is empty, we will also check that they match
+ * the scenes we are animating from and/or to.
*/
- fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean {
- val transition = transitionState as? TransitionState.Transition ?: return false
-
- return (from == null || transition.fromScene == from) &&
- (to == null || transition.toScene == to)
- }
+ fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean
/** Whether we are transitioning from [scene] to [other], or from [other] to [scene]. */
- fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean {
- return isTransitioning(from = scene, to = other) ||
- isTransitioning(from = other, to = scene)
- }
+ fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean
+}
+
+/** Create a new [SceneTransitionLayoutState] that is currently idle at scene [currentScene]. */
+fun SceneTransitionLayoutState(currentScene: SceneKey): SceneTransitionLayoutState {
+ return SceneTransitionLayoutStateImpl(currentScene, SceneTransitions.Empty)
}
@Stable
@@ -93,3 +94,50 @@ sealed interface TransitionState {
abstract val isUserInputOngoing: Boolean
}
}
+
+internal class SceneTransitionLayoutStateImpl(
+ initialScene: SceneKey,
+ internal var transitions: SceneTransitions,
+) : SceneTransitionLayoutState {
+ override var transitionState: TransitionState by
+ mutableStateOf(TransitionState.Idle(initialScene))
+ private set
+
+ /**
+ * The current [transformationSpec] associated to [transitionState]. Accessing this value makes
+ * sense only if [transitionState] is a [TransitionState.Transition].
+ */
+ internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
+
+ override fun isTransitioning(from: SceneKey?, to: SceneKey?): Boolean {
+ val transition = currentTransition ?: return false
+ return (from == null || transition.fromScene == from) &&
+ (to == null || transition.toScene == to)
+ }
+
+ override fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean {
+ return isTransitioning(from = scene, to = other) ||
+ isTransitioning(from = other, to = scene)
+ }
+
+ /** Start a new [transition], instantly interrupting any ongoing transition if there was one. */
+ internal fun startTransition(transition: TransitionState.Transition) {
+ // Compute the [TransformationSpec] when the transition starts.
+ transformationSpec =
+ transitions
+ .transitionSpec(transition.fromScene, transition.toScene)
+ .transformationSpec()
+
+ transitionState = transition
+ }
+
+ /**
+ * Notify that [transition] was finished and that we should settle to [idleScene]. This will do
+ * nothing if [transition] was interrupted since it was started.
+ */
+ internal fun finishTransition(transition: TransitionState.Transition, idleScene: SceneKey) {
+ if (transitionState == transition) {
+ transitionState = TransitionState.Idle(idleScene)
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index f91895bb0e05..3a55567d69bb 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -18,11 +18,9 @@ package com.android.compose.animation.scene
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.snap
-import androidx.compose.runtime.Stable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
-import androidx.compose.ui.util.fastMap
import com.android.compose.animation.scene.transformation.AnchoredSize
import com.android.compose.animation.scene.transformation.AnchoredTranslate
import com.android.compose.animation.scene.transformation.DrawScale
@@ -36,16 +34,17 @@ import com.android.compose.animation.scene.transformation.Transformation
import com.android.compose.animation.scene.transformation.Translate
/** The transitions configuration of a [SceneTransitionLayout]. */
-class SceneTransitions(
- internal val transitionSpecs: List<TransitionSpec>,
+class SceneTransitions
+internal constructor(
+ internal val transitionSpecs: List<TransitionSpecImpl>,
) {
- private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpec>>()
+ private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpecImpl>>()
- internal fun transitionSpec(from: SceneKey, to: SceneKey): TransitionSpec {
+ internal fun transitionSpec(from: SceneKey, to: SceneKey): TransitionSpecImpl {
return cache.getOrPut(from) { mutableMapOf() }.getOrPut(to) { findSpec(from, to) }
}
- private fun findSpec(from: SceneKey, to: SceneKey): TransitionSpec {
+ private fun findSpec(from: SceneKey, to: SceneKey): TransitionSpecImpl {
val spec = transition(from, to) { it.from == from && it.to == to }
if (spec != null) {
return spec
@@ -53,7 +52,7 @@ class SceneTransitions(
val reversed = transition(from, to) { it.from == to && it.to == from }
if (reversed != null) {
- return reversed.reverse()
+ return reversed.reversed()
}
val relaxedSpec =
@@ -67,16 +66,16 @@ class SceneTransitions(
return transition(from, to) {
(it.from == to && it.to == null) || (it.to == from && it.from == null)
}
- ?.reverse()
+ ?.reversed()
?: defaultTransition(from, to)
}
private fun transition(
from: SceneKey,
to: SceneKey,
- filter: (TransitionSpec) -> Boolean,
- ): TransitionSpec? {
- var match: TransitionSpec? = null
+ filter: (TransitionSpecImpl) -> Boolean,
+ ): TransitionSpecImpl? {
+ var match: TransitionSpecImpl? = null
transitionSpecs.fastForEach { spec ->
if (filter(spec)) {
if (match != null) {
@@ -89,28 +88,88 @@ class SceneTransitions(
}
private fun defaultTransition(from: SceneKey, to: SceneKey) =
- TransitionSpec(from, to, emptyList(), snap())
+ TransitionSpecImpl(from, to, TransformationSpec.EmptyProvider)
+
+ companion object {
+ val Empty = SceneTransitions(transitionSpecs = emptyList())
+ }
}
/** The definition of a transition between [from] and [to]. */
-@Stable
-data class TransitionSpec(
- val from: SceneKey?,
- val to: SceneKey?,
- val transformations: List<Transformation>,
- val spec: AnimationSpec<Float>,
-) {
- // TODO(b/302300957): Make sure this cache does not infinitely grow.
- private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
+interface TransitionSpec {
+ /**
+ * The scene we are transitioning from. If `null`, this spec can be used to animate from any
+ * scene.
+ */
+ val from: SceneKey?
+
+ /**
+ * The scene we are transitioning to. If `null`, this spec can be used to animate from any
+ * scene.
+ */
+ val to: SceneKey?
+
+ /**
+ * Return a reversed version of this [TransitionSpec] for a transition going from [to] to
+ * [from].
+ */
+ fun reversed(): TransitionSpec
+
+ /*
+ * The [TransformationSpec] associated to this [TransitionSpec].
+ *
+ * Note that this is called once every a transition associated to this [TransitionSpec] is
+ * started.
+ */
+ fun transformationSpec(): TransformationSpec
+}
+
+interface TransformationSpec {
+ /** The [AnimationSpec] used to animate the associated transition progress. */
+ val progressSpec: AnimationSpec<Float>
+
+ /** The list of [Transformation] applied to elements during this transition. */
+ val transformations: List<Transformation>
+
+ companion object {
+ internal val Empty =
+ TransformationSpecImpl(progressSpec = snap(), transformations = emptyList())
+ internal val EmptyProvider = { Empty }
+ }
+}
- internal fun reverse(): TransitionSpec {
- return copy(
+internal class TransitionSpecImpl(
+ override val from: SceneKey?,
+ override val to: SceneKey?,
+ private val transformationSpec: () -> TransformationSpecImpl,
+) : TransitionSpec {
+ override fun reversed(): TransitionSpecImpl {
+ return TransitionSpecImpl(
from = to,
to = from,
- transformations = transformations.fastMap { it.reverse() },
+ transformationSpec = {
+ val reverse = transformationSpec.invoke()
+ TransformationSpecImpl(
+ progressSpec = reverse.progressSpec,
+ transformations = reverse.transformations.map { it.reversed() }
+ )
+ }
)
}
+ override fun transformationSpec(): TransformationSpecImpl = this.transformationSpec.invoke()
+}
+
+/**
+ * An implementation of [TransformationSpec] that allows the quick retrieval of an element
+ * [ElementTransformations].
+ */
+internal class TransformationSpecImpl(
+ override val progressSpec: AnimationSpec<Float>,
+ override val transformations: List<Transformation>,
+) : TransformationSpec {
+ private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
+
internal fun transformations(element: ElementKey, scene: SceneKey): ElementTransformations {
return cache
.getOrPut(element) { mutableMapOf() }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index 116a66673d0a..0d3bc7d0cd85 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -27,7 +27,8 @@ internal fun Modifier.swipeToScene(gestureHandler: SceneGestureHandler): Modifie
fun Scene.shouldEnableSwipes(orientation: Orientation): Boolean =
userActions.keys.any { it is Swipe && it.direction.orientation == orientation }
- val currentScene = gestureHandler.currentScene
+ val layoutImpl = gestureHandler.layoutImpl
+ val currentScene = layoutImpl.scene(layoutImpl.state.transitionState.currentScene)
val orientation = gestureHandler.orientation
val canSwipe = currentScene.shouldEnableSwipes(orientation)
val canOppositeSwipe =
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index 8f4a36e47212..70468669297c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -44,7 +44,7 @@ internal fun transitionsImpl(
}
private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
- val transitionSpecs = mutableListOf<TransitionSpec>()
+ val transitionSpecs = mutableListOf<TransitionSpecImpl>()
override fun to(to: SceneKey, builder: TransitionBuilder.() -> Unit): TransitionSpec {
return transition(from = null, to = to, builder)
@@ -63,14 +63,15 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
to: SceneKey?,
builder: TransitionBuilder.() -> Unit,
): TransitionSpec {
- val impl = TransitionBuilderImpl().apply(builder)
- val spec =
- TransitionSpec(
- from,
- to,
- impl.transformations,
- impl.spec,
+ fun transformationSpec(): TransformationSpecImpl {
+ val impl = TransitionBuilderImpl().apply(builder)
+ return TransformationSpecImpl(
+ progressSpec = impl.spec,
+ transformations = impl.transformations,
)
+ }
+
+ val spec = TransitionSpecImpl(from, to, ::transformationSpec)
transitionSpecs.add(spec)
return spec
}
@@ -143,7 +144,7 @@ internal class TransitionBuilderImpl : TransitionBuilder {
transformations.add(
if (reversed) {
- transformation.reverse()
+ transformation.reversed()
} else {
transformation
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
index 206935558179..0cd11b9914c9 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -42,7 +42,7 @@ sealed interface Transformation {
* Reverse this transformation. This is called when we use Transition(from = A, to = B) when
* animating from B to A and there is no Transition(from = B, to = A) defined.
*/
- fun reverse(): Transformation = this
+ fun reversed(): Transformation = this
}
internal class SharedElementTransformation(
@@ -77,10 +77,10 @@ internal class RangedPropertyTransformation<T>(
val delegate: PropertyTransformation<T>,
override val range: TransformationRange,
) : PropertyTransformation<T> by delegate {
- override fun reverse(): Transformation {
+ override fun reversed(): Transformation {
return RangedPropertyTransformation(
- delegate.reverse() as PropertyTransformation<T>,
- range.reverse()
+ delegate.reversed() as PropertyTransformation<T>,
+ range.reversed()
)
}
}
@@ -102,7 +102,7 @@ data class TransformationRange(
}
/** Reverse this range. */
- fun reverse() = TransformationRange(start = reverseBound(end), end = reverseBound(start))
+ fun reversed() = TransformationRange(start = reverseBound(end), end = reverseBound(start))
/** Get the progress of this range given the global [transitionProgress]. */
fun progress(transitionProgress: Float): Float {
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
index e6224df649ca..d9ce5191f3d9 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
@@ -55,8 +55,8 @@ class SceneGestureHandlerTest {
) {
private var internalCurrentScene: SceneKey by mutableStateOf(SceneA)
- private val layoutState: SceneTransitionLayoutState =
- SceneTransitionLayoutState(internalCurrentScene)
+ private val layoutState =
+ SceneTransitionLayoutStateImpl(internalCurrentScene, EmptyTestTransitions)
val mutableUserActionsA: MutableMap<UserAction, SceneKey> =
mutableMapOf(Swipe.Up to SceneB, Swipe.Down to SceneC)
@@ -93,36 +93,24 @@ class SceneGestureHandlerTest {
private val layoutImpl =
SceneTransitionLayoutImpl(
- onChangeScene = { internalCurrentScene = it },
- builder = scenesBuilder,
- transitions = EmptyTestTransitions,
state = layoutState,
+ onChangeScene = { internalCurrentScene = it },
density = Density(1f),
edgeDetector = DefaultEdgeDetector,
transitionInterceptionThreshold = transitionInterceptionThreshold,
+ builder = scenesBuilder,
coroutineScope = coroutineScope,
)
.apply { setScenesTargetSizeForTest(LAYOUT_SIZE) }
- val sceneGestureHandler =
- SceneGestureHandler(
- layoutImpl = layoutImpl,
- orientation = Orientation.Vertical,
- coroutineScope = coroutineScope,
- )
-
- val horizontalSceneGestureHandler =
- SceneGestureHandler(
- layoutImpl = layoutImpl,
- orientation = Orientation.Horizontal,
- coroutineScope = coroutineScope,
- )
-
+ val sceneGestureHandler = layoutImpl.gestureHandler(Orientation.Vertical)
+ val horizontalSceneGestureHandler = layoutImpl.gestureHandler(Orientation.Horizontal)
val draggable = sceneGestureHandler.draggable
fun nestedScrollConnection(nestedScrollBehavior: NestedScrollBehavior) =
SceneNestedScrollHandler(
- gestureHandler = sceneGestureHandler,
+ layoutImpl,
+ orientation = sceneGestureHandler.orientation,
topOrLeftBehavior = nestedScrollBehavior,
bottomOrRightBehavior = nestedScrollBehavior,
)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index eeda8d46adfa..c5b8d9ae0d10 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -40,8 +40,8 @@ class SceneTransitionLayoutStateTest {
@Test
fun isTransitioningTo_transition() {
- val state = SceneTransitionLayoutState(TestScenes.SceneA)
- state.transitionState = transition(from = TestScenes.SceneA, to = TestScenes.SceneB)
+ val state = SceneTransitionLayoutStateImpl(TestScenes.SceneA, SceneTransitions.Empty)
+ state.startTransition(transition(from = TestScenes.SceneA, to = TestScenes.SceneB))
assertThat(state.isTransitioning()).isTrue()
assertThat(state.isTransitioning(from = TestScenes.SceneA)).isTrue()
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index fa94b25028a2..ef729921f4cd 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -55,7 +55,7 @@ class TransitionDslTest {
assertThat(transitions.transitionSpecs)
.comparingElementsUsing(
- Correspondence.transforming<TransitionSpec, Pair<SceneKey?, SceneKey?>>(
+ Correspondence.transforming<TransitionSpecImpl, Pair<SceneKey?, SceneKey?>>(
{ it?.from to it?.to },
"has (from, to) equal to"
)
@@ -70,8 +70,8 @@ class TransitionDslTest {
@Test
fun defaultTransitionSpec() {
val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) }
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.spec).isInstanceOf(SpringSpec::class.java)
+ val transformationSpec = transitions.transitionSpecs.single().transformationSpec()
+ assertThat(transformationSpec.progressSpec).isInstanceOf(SpringSpec::class.java)
}
@Test
@@ -79,9 +79,9 @@ class TransitionDslTest {
val transitions = transitions {
from(TestScenes.SceneA, to = TestScenes.SceneB) { spec = tween(durationMillis = 42) }
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.spec).isInstanceOf(TweenSpec::class.java)
- assertThat((transition.spec as TweenSpec).durationMillis).isEqualTo(42)
+ val transformationSpec = transitions.transitionSpecs.single().transformationSpec()
+ assertThat(transformationSpec.progressSpec).isInstanceOf(TweenSpec::class.java)
+ assertThat((transformationSpec.progressSpec as TweenSpec).durationMillis).isEqualTo(42)
}
@Test
@@ -90,9 +90,10 @@ class TransitionDslTest {
from(TestScenes.SceneA, to = TestScenes.SceneB) { fade(TestElements.Foo) }
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations.size).isEqualTo(1)
- assertThat(transition.transformations.single().range).isEqualTo(null)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations.size).isEqualTo(1)
+ assertThat(transformations.single().range).isEqualTo(null)
}
@Test
@@ -105,8 +106,9 @@ class TransitionDslTest {
}
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 0.1f, end = 0.8f),
@@ -127,8 +129,9 @@ class TransitionDslTest {
}
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 100 / 500f, end = 300 / 500f),
@@ -149,8 +152,9 @@ class TransitionDslTest {
}
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 1f - 0.8f, end = 1f - 0.1f),
@@ -170,9 +174,13 @@ class TransitionDslTest {
// Fetch the transition from B to A, which will automatically reverse the transition from A
// to B we defined.
- val transition =
- transitions.transitionSpec(from = TestScenes.SceneB, to = TestScenes.SceneA)
- assertThat(transition.transformations)
+ val transformations =
+ transitions
+ .transitionSpec(from = TestScenes.SceneB, to = TestScenes.SceneA)
+ .transformationSpec()
+ .transformations
+
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 1f - 0.8f, end = 1f - 0.1f),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 695d888d94f5..f1701356c134 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -18,7 +18,7 @@
package com.android.keyguard
import android.content.res.Configuration
-import android.hardware.biometrics.BiometricOverlayConstants
+import android.hardware.biometrics.BiometricRequestConstants
import android.media.AudioManager
import android.telephony.TelephonyManager
import android.testing.TestableLooper.RunWithLooper
@@ -59,6 +59,7 @@ 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.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -235,6 +236,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
sceneInteractor = sceneInteractor,
)
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
underTest =
KeyguardSecurityContainerController(
view,
@@ -763,16 +765,18 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
@Test
fun sideFpsControllerShow() {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
underTest.updateSideFpsVisibility(/* isVisible= */ true)
verify(sideFpsController)
.show(
SideFpsUiRequestSource.PRIMARY_BOUNCER,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD
)
}
@Test
fun sideFpsControllerHide() {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
underTest.updateSideFpsVisibility(/* isVisible= */ false)
verify(sideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt
new file mode 100644
index 000000000000..74f50d8c844b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt
@@ -0,0 +1,171 @@
+/*
+ * 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.accessibility.data.repository
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionRepositoryImplTest : SysuiTestCase() {
+ companion object {
+ val TEST_USER_1 = UserHandle.of(1)!!
+ val TEST_USER_2 = UserHandle.of(2)!!
+ }
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val scope = TestScope(testDispatcher)
+ private val settings: FakeSettings = FakeSettings()
+
+ private lateinit var underTest: ColorCorrectionRepository
+
+ @Before
+ fun setUp() {
+ underTest =
+ ColorCorrectionRepositoryImpl(
+ testDispatcher,
+ settings,
+ )
+ }
+
+ @Test
+ fun isEnabled_initiallyGetsSettingsValue() =
+ scope.runTest {
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ 1,
+ TEST_USER_1.identifier
+ )
+
+ underTest =
+ ColorCorrectionRepositoryImpl(
+ testDispatcher,
+ settings,
+ )
+
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+ runCurrent()
+
+ val actualValue: Boolean = underTest.isEnabled(TEST_USER_1).first()
+ Truth.assertThat(actualValue).isTrue()
+ }
+
+ @Test
+ fun isEnabled_settingUpdated_valueUpdated() =
+ scope.runTest {
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.ENABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue()
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+ }
+
+ @Test
+ fun isEnabled_settingForUserOneOnly_valueUpdatedForUserOneOnly() =
+ scope.runTest {
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_1.identifier
+ )
+ underTest.isEnabled(TEST_USER_2).launchIn(backgroundScope)
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_2.identifier
+ )
+
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse()
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.ENABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse()
+ }
+
+ @Test
+ fun setEnabled() =
+ scope.runTest {
+ val success = underTest.setIsEnabled(true, TEST_USER_1)
+ runCurrent()
+ Truth.assertThat(success).isTrue()
+
+ val actualValue =
+ settings.getIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ TEST_USER_1.identifier
+ )
+ Truth.assertThat(actualValue).isEqualTo(ColorCorrectionRepositoryImpl.ENABLED)
+ }
+
+ @Test
+ fun setDisabled() =
+ scope.runTest {
+ val success = underTest.setIsEnabled(false, TEST_USER_1)
+ runCurrent()
+ Truth.assertThat(success).isTrue()
+
+ val actualValue =
+ settings.getIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ TEST_USER_1.identifier
+ )
+ Truth.assertThat(actualValue).isEqualTo(ColorCorrectionRepositoryImpl.DISABLED)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index a1b801cd3d3f..f8321b7e7eb3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -22,9 +22,9 @@ import android.app.ActivityTaskManager
import android.content.ComponentName
import android.graphics.Insets
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_UNKNOWN
import android.hardware.biometrics.SensorLocationInternal
import android.hardware.biometrics.SensorProperties
import android.hardware.display.DisplayManager
@@ -65,6 +65,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -144,6 +145,7 @@ class SideFpsControllerTest : SysuiTestCase() {
@Before
fun setup() {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
displayRepository = FakeDisplayRepository()
displayStateRepository = FakeDisplayStateRepository()
keyguardBouncerRepository = FakeKeyguardBouncerRepository()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 90d36e7fd814..a726b7c2b075 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -17,12 +17,12 @@
package com.android.systemui.biometrics
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.RequestReason
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.testing.TestableLooper.RunWithLooper
import android.view.LayoutInflater
@@ -135,7 +135,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
}
private fun withReason(
- @ShowReason reason: Int,
+ @RequestReason reason: Int,
isDebuggable: Boolean = false,
enableDeviceEntryUdfpsRefactor: Boolean = false,
block: () -> Unit,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 97ee526b7108..dddcf18c1ede 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -43,7 +43,7 @@ import static org.mockito.Mockito.when;
import android.graphics.Rect;
import android.hardware.biometrics.BiometricFingerprintConstants;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.display.DisplayManager;
@@ -359,7 +359,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void dozeTimeTick() throws RemoteException {
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
mUdfpsController.dozeTimeTick();
verify(mUdfpsView).dozeTimeTick();
@@ -455,7 +455,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
// GIVEN overlay was showing and the udfps bouncer is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
// WHEN the overlay is hidden
@@ -469,7 +469,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void showUdfpsOverlay_callsListener() throws RemoteException {
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mFingerprintManager).onUdfpsUiEvent(FingerprintManager.UDFPS_UI_OVERLAY_SHOWN,
@@ -479,7 +479,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler), anyLong());
@@ -520,7 +520,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
reset(mWindowManager);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID,
mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_ENROLL_ENROLLING,
+ BiometricRequestConstants.REASON_ENROLL_ENROLLING,
mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mWindowManager).addView(any(), any());
@@ -555,7 +555,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// Show the overlay.
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mWindowManager).addView(any(), any());
@@ -637,7 +637,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// Show the overlay.
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -720,7 +720,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
initUdfpsController(testParams.sensorProps);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// WHEN ACTION_DOWN is received
@@ -778,7 +778,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing and screen is on and fp is running
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
// WHEN fingerprint is requested because of AOD interrupt
@@ -808,7 +808,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN AOD interrupt
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
@@ -886,7 +886,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
@@ -917,7 +917,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN AOD interrupt
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
@@ -958,7 +958,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
// Configure UdfpsView to accept the ACTION_UP event
@@ -1019,7 +1019,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN screen off
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOff();
mFgExecutor.runAllReady();
@@ -1041,7 +1041,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN showing overlay
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -1126,7 +1126,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing and a11y touch exploration NOT enabled
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(a11y);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
if (a11y) {
@@ -1148,7 +1148,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing and a11y touch exploration NOT enabled
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -1197,7 +1197,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
-1 /* pointerId */, touchData);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -1289,7 +1289,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
public void onAodInterrupt_onAcquiredGood_fingerNoLongerDown() throws RemoteException {
// GIVEN UDFPS overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// GIVEN there's been an AoD interrupt
@@ -1316,7 +1316,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
throws RemoteException {
// GIVEN UDFPS overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// GIVEN there's been an AoD interrupt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 90e0c19b7c65..a3bf3f492e6e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -33,6 +33,7 @@ import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.utils.os.FakeHandler
@@ -105,8 +106,10 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() {
job.cancel()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun shouldUpdateSideFps_show() = runTest {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
var count = 0
val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this)
repository.setPrimaryShow(true)
@@ -116,8 +119,10 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() {
job.cancel()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun shouldUpdateSideFps_hide() = runTest {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
repository.setPrimaryShow(true)
var count = 0
val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this)
@@ -128,8 +133,10 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() {
job.cancel()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun sideFpsShowing() = runTest {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
var sideFpsIsShowing = false
val job = underTest.sideFpsShowing.onEach { sideFpsIsShowing = it }.launchIn(this)
repository.setSideFpsShowing(true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
index 2b7221ec192c..6b7d2635ffa4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
@@ -304,4 +304,34 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
)
assertThat(authenticationStatus).isNull()
}
+
+ @Test
+ fun onBiometricRunningStateChanged_shouldUpdateIndicatorVisibility() =
+ testScope.runTest {
+ val shouldUpdateIndicatorVisibility by
+ collectLastValue(underTest.shouldUpdateIndicatorVisibility)
+ runCurrent()
+
+ verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
+ assertThat(shouldUpdateIndicatorVisibility).isFalse()
+
+ invokeOnCallback {
+ it.onBiometricRunningStateChanged(false, BiometricSourceType.FINGERPRINT)
+ }
+ assertThat(shouldUpdateIndicatorVisibility).isTrue()
+ }
+
+ @Test
+ fun onStrongAuthStateChanged_shouldUpdateIndicatorVisibility() =
+ testScope.runTest {
+ val shouldUpdateIndicatorVisibility by
+ collectLastValue(underTest.shouldUpdateIndicatorVisibility)
+ runCurrent()
+
+ verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
+ assertThat(shouldUpdateIndicatorVisibility).isFalse()
+
+ invokeOnCallback { it.onStrongAuthStateChanged(0) }
+ assertThat(shouldUpdateIndicatorVisibility).isTrue()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt
new file mode 100644
index 000000000000..8ee6d2005350
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain
+
+import android.graphics.drawable.TestStubDrawable
+import android.widget.Switch
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.impl.colorcorrection.qsColorCorrectionTileConfig
+import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionTileMapperTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val colorCorrectionTileConfig = kosmos.qsColorCorrectionTileConfig
+ private val subtitleArray =
+ context.resources.getStringArray(R.array.tile_states_color_correction)
+ // Using lazy (versus =) to make sure we override the right context -- see b/311612168
+ private val mapper by lazy {
+ ColorCorrectionTileMapper(
+ context.orCreateTestableResources
+ .apply { addOverride(R.drawable.ic_qs_color_correction, TestStubDrawable()) }
+ .resources,
+ context.theme
+ )
+ }
+
+ @Test
+ fun disabledModel() {
+ val inputModel = ColorCorrectionTileModel(false)
+
+ val outputState = mapper.map(colorCorrectionTileConfig, inputModel)
+
+ val expectedState =
+ createColorCorrectionTileState(QSTileState.ActivationState.INACTIVE, subtitleArray[1])
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun enabledModel() {
+ val inputModel = ColorCorrectionTileModel(true)
+
+ val outputState = mapper.map(colorCorrectionTileConfig, inputModel)
+
+ val expectedState =
+ createColorCorrectionTileState(QSTileState.ActivationState.ACTIVE, subtitleArray[2])
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ private fun createColorCorrectionTileState(
+ activationState: QSTileState.ActivationState,
+ secondaryLabel: String
+ ): QSTileState {
+ val label = context.getString(R.string.quick_settings_color_correction_label)
+ return QSTileState(
+ { Icon.Loaded(context.getDrawable(R.drawable.ic_qs_color_correction)!!, null) },
+ label,
+ activationState,
+ secondaryLabel,
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK),
+ label,
+ null,
+ QSTileState.SideViewIcon.None,
+ QSTileState.EnabledState.ENABLED,
+ Switch::class.qualifiedName
+ )
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
new file mode 100644
index 000000000000..8c612acad887
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeColorCorrectionRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.toCollection
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionTileDataInteractorTest : SysuiTestCase() {
+
+ private val colorCorrectionRepository = FakeColorCorrectionRepository()
+ private val underTest: ColorCorrectionTileDataInteractor =
+ ColorCorrectionTileDataInteractor(colorCorrectionRepository)
+
+ @Test
+ fun alwaysAvailable() = runTest {
+ val availability = underTest.availability(TEST_USER).toCollection(mutableListOf())
+
+ assertThat(availability).hasSize(1)
+ assertThat(availability.last()).isTrue()
+ }
+
+ @Test
+ fun dataMatchesTheRepository() = runTest {
+ val dataList: List<ColorCorrectionTileModel> by
+ collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
+ runCurrent()
+
+ colorCorrectionRepository.setIsEnabled(true, TEST_USER)
+ runCurrent()
+
+ colorCorrectionRepository.setIsEnabled(false, TEST_USER)
+ runCurrent()
+
+ assertThat(dataList).hasSize(3)
+ assertThat(dataList.map { it.isEnabled }).isEqualTo(listOf(false, true, false))
+ }
+
+ private companion object {
+ val TEST_USER = UserHandle.of(1)!!
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
new file mode 100644
index 000000000000..3049cc079a1c
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
@@ -0,0 +1,89 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.os.UserHandle
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeColorCorrectionRepository
+import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
+import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionTileUserActionInteractorTest : SysuiTestCase() {
+
+ private val testUser = UserHandle.CURRENT
+ private val repository = FakeColorCorrectionRepository()
+ private val inputHandler = FakeQSTileIntentUserInputHandler()
+
+ private val underTest =
+ ColorCorrectionUserActionInteractor(
+ repository,
+ inputHandler,
+ )
+
+ @Test
+ fun handleClickWhenEnabled() = runTest {
+ val wasEnabled = true
+ repository.setIsEnabled(wasEnabled, testUser)
+
+ underTest.handleInput(QSTileInputTestKtx.click(ColorCorrectionTileModel(wasEnabled)))
+
+ assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleClickWhenDisabled() = runTest {
+ val wasEnabled = false
+ repository.setIsEnabled(wasEnabled, testUser)
+
+ underTest.handleInput(QSTileInputTestKtx.click(ColorCorrectionTileModel(wasEnabled)))
+
+ assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleLongClickWhenDisabled() = runTest {
+ val enabled = false
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(ColorCorrectionTileModel(enabled)))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+ }
+ }
+
+ @Test
+ fun handleLongClickWhenEnabled() = runTest {
+ val enabled = true
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(ColorCorrectionTileModel(enabled)))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/CustomTilePackageUpdatesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/CustomTilePackageUpdatesRepositoryTest.kt
index 4a221134ce67..2eeb75e3443b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/CustomTilePackageUpdatesRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/CustomTilePackageUpdatesRepositoryTest.kt
@@ -16,23 +16,27 @@
package com.android.systemui.qs.tiles.impl.custom
+import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.qs.external.TileLifecycleManager
-import com.android.systemui.qs.external.TileServiceManager
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTilePackageUpdatesRepository
import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTilePackageUpdatesRepositoryImpl
-import com.android.systemui.qs.tiles.impl.custom.data.repository.FakeCustomTileDefaultsRepository
-import com.android.systemui.qs.tiles.impl.custom.data.repository.FakeCustomTileDefaultsRepository.DefaultsRequest
+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.nullable
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -49,14 +53,12 @@ import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
+@SuppressLint("UnspecifiedRegisterReceiverFlag") // Not needed in the test
class CustomTilePackageUpdatesRepositoryTest : SysuiTestCase() {
- @Mock private lateinit var tileServiceManager: TileServiceManager
+ @Mock private lateinit var mockedContext: Context
+ @Captor private lateinit var listenerCaptor: ArgumentCaptor<BroadcastReceiver>
- @Captor
- private lateinit var listenerCaptor: ArgumentCaptor<TileLifecycleManager.TileChangeListener>
-
- private val defaultsRepository = FakeCustomTileDefaultsRepository()
private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
@@ -69,37 +71,29 @@ class CustomTilePackageUpdatesRepositoryTest : SysuiTestCase() {
underTest =
CustomTilePackageUpdatesRepositoryImpl(
TileSpec.create(COMPONENT_1),
- USER,
- tileServiceManager,
- defaultsRepository,
+ mockedContext,
testScope.backgroundScope,
+ testDispatcher,
)
}
@Test
- fun packageChangesUpdatesDefaults() =
+ fun packageChangesEmittedForTilePassing() =
testScope.runTest {
- val events = mutableListOf<Unit>()
- underTest.packageChanges.onEach { events.add(it) }.launchIn(backgroundScope)
+ val events by collectValues(underTest.getPackageChangesForUser(USER_1))
runCurrent()
- verify(tileServiceManager).setTileChangeListener(capture(listenerCaptor))
- emitPackageChange()
+ emitPackageChange(COMPONENT_1)
runCurrent()
assertThat(events).hasSize(1)
- assertThat(defaultsRepository.defaultsRequests).isNotEmpty()
- assertThat(defaultsRepository.defaultsRequests.last())
- .isEqualTo(DefaultsRequest(USER, COMPONENT_1, true))
}
@Test
- fun packageChangesEmittedOnlyForTheTile() =
+ fun packageChangesEmittedForAnotherTileIgnored() =
testScope.runTest {
- val events = mutableListOf<Unit>()
- underTest.packageChanges.onEach { events.add(it) }.launchIn(backgroundScope)
+ val events by collectValues(underTest.getPackageChangesForUser(USER_1))
runCurrent()
- verify(tileServiceManager).setTileChangeListener(capture(listenerCaptor))
emitPackageChange(COMPONENT_2)
runCurrent()
@@ -107,12 +101,60 @@ class CustomTilePackageUpdatesRepositoryTest : SysuiTestCase() {
assertThat(events).isEmpty()
}
- private fun emitPackageChange(componentName: ComponentName = COMPONENT_1) {
- listenerCaptor.value.onTileChanged(componentName)
+ @Test
+ fun unsupportedActionDoesntEmmit() =
+ testScope.runTest {
+ val events by collectValues(underTest.getPackageChangesForUser(USER_1))
+ runCurrent()
+
+ verify(mockedContext)
+ .registerReceiverAsUser(
+ capture(listenerCaptor),
+ any(),
+ any(),
+ nullable(),
+ nullable()
+ )
+ listenerCaptor.value.onReceive(mockedContext, Intent(Intent.ACTION_MAIN))
+ runCurrent()
+
+ assertThat(events).isEmpty()
+ }
+
+ @Test
+ fun cachesCallsPerUser() =
+ testScope.runTest {
+ underTest.getPackageChangesForUser(USER_1).launchIn(backgroundScope)
+ underTest.getPackageChangesForUser(USER_1).launchIn(backgroundScope)
+ underTest.getPackageChangesForUser(USER_2).launchIn(backgroundScope)
+ underTest.getPackageChangesForUser(USER_2).launchIn(backgroundScope)
+ runCurrent()
+
+ // Register receiver once per each user
+ verify(mockedContext)
+ .registerReceiverAsUser(any(), eq(USER_1), any(), nullable(), nullable())
+ verify(mockedContext)
+ .registerReceiverAsUser(any(), eq(USER_2), any(), nullable(), nullable())
+ }
+
+ private fun emitPackageChange(componentName: ComponentName) {
+ verify(mockedContext)
+ .registerReceiverAsUser(capture(listenerCaptor), any(), any(), nullable(), nullable())
+ listenerCaptor.value.onReceive(
+ mockedContext,
+ Intent(Intent.ACTION_PACKAGE_CHANGED).apply {
+ type = IntentFilter.SCHEME_PACKAGE
+ putExtra(
+ Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST,
+ arrayOf(componentName.packageName)
+ )
+ }
+ )
}
private companion object {
- val USER = UserHandle(0)
+ val USER_1 = UserHandle(1)
+ val USER_2 = UserHandle(2)
val COMPONENT_1 = ComponentName("pkg.test.1", "cls.test")
val COMPONENT_2 = ComponentName("pkg.test.2", "cls.test")
}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml b/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
index 48769fdebd99..073f090027ba 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
@@ -18,8 +18,6 @@
<TextView
android:id="@+id/digit_text"
style="@style/Widget.TextView.NumPadKey.Digit"
- android:autoSizeMaxTextSize="32sp"
- android:autoSizeTextType="uniform"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 88f7bcd5d907..2cca9510417a 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -69,7 +69,7 @@
<item name="android:singleLine">true</item>
<item name="android:gravity">center_horizontal|center_vertical</item>
<item name="android:background">@null</item>
- <item name="android:textSize">32sp</item>
+ <item name="android:textSize">32dp</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
<item name="android:paddingBottom">-16dp</item>
diff --git a/packages/SystemUI/res/layout/sidefps_view.xml b/packages/SystemUI/res/layout/sidefps_view.xml
index 4d952209da6f..fc4bf8a65643 100644
--- a/packages/SystemUI/res/layout/sidefps_view.xml
+++ b/packages/SystemUI/res/layout/sidefps_view.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.SideFpsLottieViewWrapper
+<com.android.systemui.biometrics.SideFpsIndicatorView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sidefps_animation"
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
index 80f70a0cd2f2..30648291366a 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
@@ -37,6 +37,10 @@ data class BiometricModalities(
val hasSfps: Boolean
get() = hasFingerprint && fingerprintProperties!!.isAnySidefpsType
+ /** If UDFPS authentication is available. */
+ val hasUdfps: Boolean
+ get() = hasFingerprint && fingerprintProperties!!.isAnyUdfpsType
+
/** If fingerprint authentication is available (and [faceProperties] is non-null). */
val hasFace: Boolean
get() = faceProperties != null
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 5c206e95966b..5d63c2a92ba8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -281,7 +281,10 @@ public class KeyguardPatternView extends KeyguardInputView
setAlpha(1f);
mAppearAnimationUtils.startAnimation2d(
mLockPatternView.getCellStates(),
- () -> enableClipping(true),
+ () -> {
+ enableClipping(true);
+ mLockPatternView.invalidate();
+ },
KeyguardPatternView.this);
});
if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 0a4378e07b45..cce2018f733f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -38,7 +38,7 @@ import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Resources;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.media.AudioManager;
import android.metrics.LogMaker;
import android.os.SystemClock;
@@ -74,6 +74,7 @@ import com.android.systemui.Gefingerpoken;
import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate;
import com.android.systemui.biometrics.SideFpsController;
import com.android.systemui.biometrics.SideFpsUiRequestSource;
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor;
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.FalsingA11yDelegate;
@@ -486,7 +487,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mSceneContainerFlags = sceneContainerFlags;
mGlobalSettings = globalSettings;
mSessionTracker = sessionTracker;
- mSideFpsController = sideFpsController;
+ if (SideFpsControllerRefactor.isEnabled()) {
+ mSideFpsController = Optional.empty();
+ } else {
+ mSideFpsController = sideFpsController;
+ }
mFalsingA11yDelegate = falsingA11yDelegate;
mTelephonyManager = telephonyManager;
mViewMediatorCallback = viewMediatorCallback;
@@ -569,12 +574,14 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mView.clearFocus();
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/**
* Shows and hides the side finger print sensor animation.
*
* @param isVisible sets whether we show or hide the side fps animation
*/
public void updateSideFpsVisibility(boolean isVisible) {
+ SideFpsControllerRefactor.assertInLegacyMode();
if (!mSideFpsController.isPresent()) {
return;
}
@@ -582,7 +589,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
if (isVisible) {
mSideFpsController.get().show(
SideFpsUiRequestSource.PRIMARY_BOUNCER,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD
);
} else {
mSideFpsController.get().hide(SideFpsUiRequestSource.PRIMARY_BOUNCER);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
index ca859de73a36..24aa11e10f30 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 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.
@@ -16,61 +16,16 @@
package com.android.systemui.accessibility
-import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.qs.tiles.ColorCorrectionTile
-import com.android.systemui.qs.tiles.ColorInversionTile
-import com.android.systemui.qs.tiles.DreamTile
-import com.android.systemui.qs.tiles.FontScalingTile
-import com.android.systemui.qs.tiles.NightDisplayTile
-import com.android.systemui.qs.tiles.OneHandedModeTile
-import com.android.systemui.qs.tiles.ReduceBrightColorsTile
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepositoryImpl
+import com.android.systemui.accessibility.qs.QSAccessibilityModule
import dagger.Binds
import dagger.Module
-import dagger.multibindings.IntoMap
-import dagger.multibindings.StringKey
-@Module
+@Module(includes = [QSAccessibilityModule::class])
interface AccessibilityModule {
-
- /** Inject ColorInversionTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(ColorInversionTile.TILE_SPEC)
- fun bindColorInversionTile(colorInversionTile: ColorInversionTile): QSTileImpl<*>
-
- /** Inject NightDisplayTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(NightDisplayTile.TILE_SPEC)
- fun bindNightDisplayTile(nightDisplayTile: NightDisplayTile): QSTileImpl<*>
-
- /** Inject ReduceBrightColorsTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(ReduceBrightColorsTile.TILE_SPEC)
- fun bindReduceBrightColorsTile(reduceBrightColorsTile: ReduceBrightColorsTile): QSTileImpl<*>
-
- /** Inject OneHandedModeTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(OneHandedModeTile.TILE_SPEC)
- fun bindOneHandedModeTile(oneHandedModeTile: OneHandedModeTile): QSTileImpl<*>
-
- /** Inject ColorCorrectionTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(ColorCorrectionTile.TILE_SPEC)
- fun bindColorCorrectionTile(colorCorrectionTile: ColorCorrectionTile): QSTileImpl<*>
-
- /** Inject DreamTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(DreamTile.TILE_SPEC)
- fun bindDreamTile(dreamTile: DreamTile): QSTileImpl<*>
-
- /** Inject FontScalingTile into tileMap in QSModule */
@Binds
- @IntoMap
- @StringKey(FontScalingTile.TILE_SPEC)
- fun bindFontScalingTile(fontScalingTile: FontScalingTile): QSTileImpl<*>
+ abstract fun colorCorrectionRepository(
+ impl: ColorCorrectionRepositoryImpl
+ ): ColorCorrectionRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.kt
new file mode 100644
index 000000000000..6483ae44d5ec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.accessibility.data.repository
+
+import android.os.UserHandle
+import android.provider.Settings.Secure
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
+
+/** Provides data related to color correction. */
+interface ColorCorrectionRepository {
+ /** Observable for whether color correction is enabled */
+ fun isEnabled(userHandle: UserHandle): Flow<Boolean>
+
+ /** Sets color correction enabled state. */
+ suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean
+}
+
+@SysUISingleton
+class ColorCorrectionRepositoryImpl
+@Inject
+constructor(
+ @Background private val bgCoroutineContext: CoroutineContext,
+ private val secureSettings: SecureSettings,
+) : ColorCorrectionRepository {
+
+ companion object {
+ const val SETTING_NAME = Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED
+ const val DISABLED = 0
+ const val ENABLED = 1
+ }
+
+ override fun isEnabled(userHandle: UserHandle): Flow<Boolean> =
+ secureSettings
+ .observerFlow(userHandle.identifier, SETTING_NAME)
+ .onStart { emit(Unit) }
+ .map { secureSettings.getIntForUser(SETTING_NAME, userHandle.identifier) == ENABLED }
+ .distinctUntilChanged()
+ .flowOn(bgCoroutineContext)
+
+ override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean =
+ withContext(bgCoroutineContext) {
+ secureSettings.putIntForUser(
+ SETTING_NAME,
+ if (isEnabled) ENABLED else DISABLED,
+ userHandle.identifier
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
new file mode 100644
index 000000000000..df7fdb8e6058
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.accessibility.qs
+
+import com.android.systemui.qs.QsEventLogger
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.tiles.ColorCorrectionTile
+import com.android.systemui.qs.tiles.ColorInversionTile
+import com.android.systemui.qs.tiles.DreamTile
+import com.android.systemui.qs.tiles.FontScalingTile
+import com.android.systemui.qs.tiles.NightDisplayTile
+import com.android.systemui.qs.tiles.OneHandedModeTile
+import com.android.systemui.qs.tiles.ReduceBrightColorsTile
+import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.ColorCorrectionTileMapper
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionTileDataInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionUserActionInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
+import com.android.systemui.res.R
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.IntoMap
+import dagger.multibindings.StringKey
+
+@Module
+interface QSAccessibilityModule {
+
+ /** Inject ColorInversionTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(ColorInversionTile.TILE_SPEC)
+ fun bindColorInversionTile(colorInversionTile: ColorInversionTile): QSTileImpl<*>
+
+ /** Inject NightDisplayTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(NightDisplayTile.TILE_SPEC)
+ fun bindNightDisplayTile(nightDisplayTile: NightDisplayTile): QSTileImpl<*>
+
+ /** Inject ReduceBrightColorsTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(ReduceBrightColorsTile.TILE_SPEC)
+ fun bindReduceBrightColorsTile(reduceBrightColorsTile: ReduceBrightColorsTile): QSTileImpl<*>
+
+ /** Inject OneHandedModeTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(OneHandedModeTile.TILE_SPEC)
+ fun bindOneHandedModeTile(oneHandedModeTile: OneHandedModeTile): QSTileImpl<*>
+
+ /** Inject ColorCorrectionTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(ColorCorrectionTile.TILE_SPEC)
+ fun bindColorCorrectionTile(colorCorrectionTile: ColorCorrectionTile): QSTileImpl<*>
+
+ /** Inject DreamTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(DreamTile.TILE_SPEC)
+ fun bindDreamTile(dreamTile: DreamTile): QSTileImpl<*>
+
+ /** Inject FontScalingTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(FontScalingTile.TILE_SPEC)
+ fun bindFontScalingTile(fontScalingTile: FontScalingTile): QSTileImpl<*>
+
+ companion object {
+
+ const val COLOR_CORRECTION_TILE_SPEC = "color_correction"
+
+ @Provides
+ @IntoMap
+ @StringKey(COLOR_CORRECTION_TILE_SPEC)
+ fun provideColorCorrectionTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
+ QSTileConfig(
+ tileSpec = TileSpec.create(COLOR_CORRECTION_TILE_SPEC),
+ uiConfig =
+ QSTileUIConfig.Resource(
+ iconRes = R.drawable.ic_qs_color_correction,
+ labelRes = R.string.quick_settings_color_correction_label,
+ ),
+ instanceId = uiEventLogger.getNewInstanceId(),
+ )
+
+ /** Inject ColorCorrectionTile into tileViewModelMap in QSModule */
+ @Provides
+ @IntoMap
+ @StringKey(COLOR_CORRECTION_TILE_SPEC)
+ fun provideColorCorrectionTileViewModel(
+ factory: QSTileViewModelFactory.Static<ColorCorrectionTileModel>,
+ mapper: ColorCorrectionTileMapper,
+ stateInteractor: ColorCorrectionTileDataInteractor,
+ userActionInteractor: ColorCorrectionUserActionInteractor
+ ): QSTileViewModel =
+ factory.create(
+ TileSpec.create(COLOR_CORRECTION_TILE_SPEC),
+ userActionInteractor,
+ stateInteractor,
+ mapper,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 877afce7fe65..5fba761b2f09 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -70,6 +70,7 @@ import com.android.systemui.CoreStartable;
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor;
import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
@@ -88,6 +89,8 @@ import com.android.systemui.util.concurrency.Execution;
import dagger.Lazy;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -101,7 +104,6 @@ import java.util.Set;
import javax.inject.Inject;
import javax.inject.Provider;
-import kotlin.Unit;
import kotlinx.coroutines.CoroutineScope;
/**
@@ -317,7 +319,9 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null;
if (mSidefpsProps != null) {
- mSideFpsController = mSidefpsControllerFactory.get();
+ if (!SideFpsControllerRefactor.isEnabled()) {
+ mSideFpsController = mSidefpsControllerFactory.get();
+ }
}
mFingerprintManager.registerBiometricStateListener(new BiometricStateListener() {
@@ -1194,7 +1198,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
* Whether the passed userId has enrolled SFPS.
*/
public boolean isSfpsEnrolled(int userId) {
- if (mSideFpsController == null) {
+ if (mSidefpsProps == null) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 91cee9e51a93..ac99fc69b2b5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -23,9 +23,9 @@ import android.graphics.PixelFormat
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
import android.hardware.biometrics.SensorLocationInternal
import android.hardware.display.DisplayManager
import android.hardware.fingerprint.FingerprintManager
@@ -58,6 +58,7 @@ import com.android.internal.annotations.VisibleForTesting
import com.android.keyguard.KeyguardPINView
import com.android.systemui.Dumpable
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -91,7 +92,7 @@ constructor(
@Main private val mainExecutor: DelayableExecutor,
@Main private val handler: Handler,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
- @Application private val scope: CoroutineScope,
+ @Application private val applicationScope: CoroutineScope,
dumpManager: DumpManager,
fpsUnlockTracker: FpsUnlockTracker
) : Dumpable {
@@ -110,7 +111,7 @@ constructor(
handler,
sensorProps,
{ reason -> onOrientationChanged(reason) },
- BiometricOverlayConstants.REASON_UNKNOWN
+ BiometricRequestConstants.REASON_UNKNOWN
)
@VisibleForTesting val orientationListener = orientationReasonListener.orientationListener
@@ -169,25 +170,27 @@ constructor(
}
init {
- fpsUnlockTracker.startTracking()
- fingerprintManager?.setSidefpsController(
- object : ISidefpsController.Stub() {
- override fun show(
- sensorId: Int,
- @BiometricOverlayConstants.ShowReason reason: Int
- ) =
- if (reason.isReasonToAutoShow(activityTaskManager)) {
- show(SideFpsUiRequestSource.AUTO_SHOW, reason)
- } else {
- hide(SideFpsUiRequestSource.AUTO_SHOW)
- }
-
- override fun hide(sensorId: Int) = hide(SideFpsUiRequestSource.AUTO_SHOW)
- }
- )
- listenForAlternateBouncerVisibility()
+ if (!SideFpsControllerRefactor.isEnabled) {
+ fpsUnlockTracker.startTracking()
+ fingerprintManager?.setSidefpsController(
+ object : ISidefpsController.Stub() {
+ override fun show(
+ sensorId: Int,
+ @BiometricRequestConstants.RequestReason reason: Int
+ ) =
+ if (reason.isReasonToAutoShow(activityTaskManager)) {
+ show(SideFpsUiRequestSource.AUTO_SHOW, reason)
+ } else {
+ hide(SideFpsUiRequestSource.AUTO_SHOW)
+ }
+
+ override fun hide(sensorId: Int) = hide(SideFpsUiRequestSource.AUTO_SHOW)
+ }
+ )
+ listenForAlternateBouncerVisibility()
- dumpManager.registerDumpable(this)
+ dumpManager.registerDumpable(this)
+ }
}
private fun listenForAlternateBouncerVisibility() {
@@ -195,7 +198,7 @@ constructor(
alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, "SideFpsController")
}
- scope.launch {
+ applicationScope.launch {
alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
if (isVisible) {
show(SideFpsUiRequestSource.ALTERNATE_BOUNCER, REASON_AUTH_KEYGUARD)
@@ -209,8 +212,10 @@ constructor(
/** Shows the side fps overlay if not already shown. */
fun show(
request: SideFpsUiRequestSource,
- @BiometricOverlayConstants.ShowReason reason: Int = BiometricOverlayConstants.REASON_UNKNOWN
+ @BiometricRequestConstants.RequestReason
+ reason: Int = BiometricRequestConstants.REASON_UNKNOWN
) {
+ SideFpsControllerRefactor.assertInLegacyMode()
if (!displayStateInteractor.isInRearDisplayMode.value) {
requests.add(request)
mainExecutor.execute {
@@ -229,6 +234,7 @@ constructor(
/** Hides the fps overlay if shown. */
fun hide(request: SideFpsUiRequestSource) {
+ SideFpsControllerRefactor.assertInLegacyMode()
requests.remove(request)
mainExecutor.execute {
if (requests.isEmpty()) {
@@ -239,6 +245,7 @@ constructor(
/** Hide the arrow indicator. */
fun hideIndicator() {
+ SideFpsControllerRefactor.assertInLegacyMode()
val lottieAnimationView =
overlayView?.findViewById(R.id.sidefps_animation) as LottieAnimationView?
lottieAnimationView?.visibility = INVISIBLE
@@ -246,6 +253,7 @@ constructor(
/** Show the arrow indicator. */
fun showIndicator() {
+ SideFpsControllerRefactor.assertInLegacyMode()
val lottieAnimationView =
overlayView?.findViewById(R.id.sidefps_animation) as LottieAnimationView?
lottieAnimationView?.visibility = VISIBLE
@@ -279,13 +287,13 @@ constructor(
pw.println("currentRotation=${displayInfo.rotation}")
}
- private fun onOrientationChanged(@BiometricOverlayConstants.ShowReason reason: Int) {
+ private fun onOrientationChanged(@BiometricRequestConstants.RequestReason reason: Int) {
if (overlayView != null) {
createOverlayForDisplay(reason)
}
}
- private fun createOverlayForDisplay(@BiometricOverlayConstants.ShowReason reason: Int) {
+ private fun createOverlayForDisplay(@BiometricRequestConstants.RequestReason reason: Int) {
val view = layoutInflater.inflate(R.layout.sidefps_view, null, false)
overlayView = view
val display = context.display!!
@@ -395,7 +403,7 @@ private val FingerprintManager?.sideFpsSensorProperties: FingerprintSensorProper
/** Returns [True] when the device has a side fingerprint sensor. */
fun FingerprintManager?.hasSideFpsSensor(): Boolean = this?.sideFpsSensorProperties != null
-@BiometricOverlayConstants.ShowReason
+@BiometricRequestConstants.RequestReason
private fun Int.isReasonToAutoShow(activityTaskManager: ActivityTaskManager): Boolean =
when (this) {
REASON_AUTH_KEYGUARD -> false
@@ -434,7 +442,7 @@ private fun Display.isNaturalOrientation(): Boolean =
private fun LottieAnimationView.addOverlayDynamicColor(
context: Context,
- @BiometricOverlayConstants.ShowReason reason: Int
+ @BiometricRequestConstants.RequestReason reason: Int
) {
fun update() {
val isKeyguard = reason == REASON_AUTH_KEYGUARD
@@ -501,7 +509,7 @@ class OrientationReasonListener(
handler: Handler,
sensorProps: FingerprintSensorPropertiesInternal,
onOrientationChanged: (reason: Int) -> Unit,
- @BiometricOverlayConstants.ShowReason var reason: Int
+ @BiometricRequestConstants.RequestReason var reason: Int
) {
val orientationListener =
BiometricDisplayListener(
@@ -516,7 +524,7 @@ class OrientationReasonListener(
/**
* The source of a request to show the side fps visual indicator. This is distinct from
- * [BiometricOverlayConstants] which corrresponds with the reason fingerprint authentication is
+ * [BiometricRequestConstants] which corresponds with the reason fingerprint authentication is
* requested.
*/
enum class SideFpsUiRequestSource {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsIndicatorView.kt
index e98f6db12d34..d5e25ac84aba 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsIndicatorView.kt
@@ -19,6 +19,6 @@ import android.content.Context
import android.util.AttributeSet
import com.android.systemui.util.wrapper.LottieViewWrapper
-class SideFpsLottieViewWrapper
+class SideFpsIndicatorView
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index bb6ef41bdfd3..65668b56a9f3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -19,10 +19,10 @@ package com.android.systemui.biometrics;
import static android.app.StatusBarManager.SESSION_BIOMETRIC_PROMPT;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR;
import static com.android.internal.util.LatencyTracker.ACTION_UDFPS_ILLUMINATE;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -106,6 +106,8 @@ import com.android.systemui.util.time.SystemClock;
import dagger.Lazy;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -115,8 +117,6 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Provider;
-import kotlin.Unit;
-
import kotlinx.coroutines.ExperimentalCoroutinesApi;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 452cd6a7c4df..dae6d08f7331 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -21,13 +21,13 @@ import android.annotation.UiThread
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
-import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import android.hardware.biometrics.BiometricRequestConstants.RequestReason
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.os.Build
import android.os.RemoteException
@@ -96,7 +96,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider,
val requestId: Long,
- @ShowReason val requestReason: Int,
+ @RequestReason val requestReason: Int,
private val controllerCallback: IUdfpsOverlayControllerCallback,
private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
private val activityLaunchAnimator: ActivityLaunchAnimator,
@@ -461,7 +461,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
}
}
-@ShowReason
+@RequestReason
private fun Int.isImportantForAccessibility() =
this == REASON_ENROLL_FIND_SENSOR ||
this == REASON_ENROLL_ENROLLING ||
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
index e3dbcb523258..88b9e1bdfd97 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
@@ -18,13 +18,13 @@ package com.android.systemui.biometrics
import android.content.Context
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import android.hardware.biometrics.BiometricRequestConstants.REASON_UNKNOWN
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.util.Log
import android.view.LayoutInflater
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
index 72fcfe777e79..8ae6f87f4f83 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
@@ -18,8 +18,11 @@ package com.android.systemui.biometrics.dagger
import android.content.res.Resources
import com.android.internal.R
+import com.android.systemui.CoreStartable
import com.android.systemui.biometrics.EllipseOverlapDetectorParams
import com.android.systemui.biometrics.UdfpsUtils
+import com.android.systemui.biometrics.data.repository.BiometricStatusRepository
+import com.android.systemui.biometrics.data.repository.BiometricStatusRepositoryImpl
import com.android.systemui.biometrics.data.repository.DisplayStateRepository
import com.android.systemui.biometrics.data.repository.DisplayStateRepositoryImpl
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
@@ -33,11 +36,14 @@ import com.android.systemui.biometrics.data.repository.PromptRepositoryImpl
import com.android.systemui.biometrics.udfps.BoundingBoxOverlapDetector
import com.android.systemui.biometrics.udfps.EllipseOverlapDetector
import com.android.systemui.biometrics.udfps.OverlapDetector
+import com.android.systemui.biometrics.ui.binder.SideFpsOverlayViewBinder
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.concurrency.ThreadFactory
import dagger.Binds
import dagger.Module
import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
import java.util.concurrent.Executor
import javax.inject.Qualifier
@@ -46,6 +52,11 @@ import javax.inject.Qualifier
interface BiometricsModule {
@Binds
+ @IntoMap
+ @ClassKey(SideFpsOverlayViewBinder::class)
+ fun bindsSideFpsOverlayViewBinder(viewBinder: SideFpsOverlayViewBinder): CoreStartable
+
+ @Binds
@SysUISingleton
fun faceSettings(impl: FaceSettingsRepositoryImpl): FaceSettingsRepository
@@ -57,6 +68,10 @@ interface BiometricsModule {
@Binds
@SysUISingleton
+ fun biometricStatusRepository(impl: BiometricStatusRepositoryImpl): BiometricStatusRepository
+
+ @Binds
+ @SysUISingleton
fun fingerprintRepository(
impl: FingerprintPropertyRepositoryImpl
): FingerprintPropertyRepository
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt
new file mode 100644
index 000000000000..ad2136af4b86
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.biometrics.data.repository
+
+import android.hardware.biometrics.AuthenticationStateListener
+import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.shareIn
+
+/** A repository for the state of biometric authentication. */
+interface BiometricStatusRepository {
+ /**
+ * The logical reason for the current fingerprint auth operation if one is on-going, otherwise
+ * [NotRunning].
+ */
+ val fingerprintAuthenticationReason: Flow<AuthenticationReason>
+}
+
+@SysUISingleton
+class BiometricStatusRepositoryImpl
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val biometricManager: BiometricManager?
+) : BiometricStatusRepository {
+
+ override val fingerprintAuthenticationReason: Flow<AuthenticationReason> =
+ conflatedCallbackFlow {
+ val updateFingerprintAuthenticateReason = { reason: AuthenticationReason ->
+ trySendWithFailureLogging(
+ reason,
+ TAG,
+ "Error sending fingerprintAuthenticateReason reason"
+ )
+ }
+
+ val authenticationStateListener =
+ object : AuthenticationStateListener.Stub() {
+ override fun onAuthenticationStarted(requestReason: Int) {
+ val authenticationReason =
+ when (requestReason) {
+ REASON_AUTH_BP ->
+ AuthenticationReason.BiometricPromptAuthentication
+ REASON_AUTH_KEYGUARD ->
+ AuthenticationReason.DeviceEntryAuthentication
+ REASON_AUTH_OTHER -> AuthenticationReason.OtherAuthentication
+ REASON_AUTH_SETTINGS ->
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.OTHER
+ )
+ REASON_ENROLL_ENROLLING ->
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_ENROLLING
+ )
+ REASON_ENROLL_FIND_SENSOR ->
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_FIND_SENSOR
+ )
+ else -> AuthenticationReason.Unknown
+ }
+ updateFingerprintAuthenticateReason(authenticationReason)
+ }
+
+ override fun onAuthenticationStopped() {
+ updateFingerprintAuthenticateReason(AuthenticationReason.NotRunning)
+ }
+ }
+
+ updateFingerprintAuthenticateReason(AuthenticationReason.NotRunning)
+ biometricManager?.registerAuthenticationStateListener(authenticationStateListener)
+ awaitClose {
+ biometricManager?.unregisterAuthenticationStateListener(
+ authenticationStateListener
+ )
+ }
+ }
+ .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1)
+
+ companion object {
+ private const val TAG = "BiometricStatusRepositoryImpl"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
index b9b2fd8875d9..ec3fd9f7da35 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
@@ -15,6 +15,8 @@
*/
package com.android.systemui.biometrics.domain
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
import com.android.systemui.biometrics.domain.interactor.CredentialInteractor
import com.android.systemui.biometrics.domain.interactor.CredentialInteractorImpl
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
@@ -38,6 +40,12 @@ interface BiometricsDomainLayerModule {
@Binds
@SysUISingleton
+ fun providesBiometricStatusInteractor(
+ impl: BiometricStatusInteractorImpl
+ ): BiometricStatusInteractor
+
+ @Binds
+ @SysUISingleton
fun providesCredentialInteractor(impl: CredentialInteractorImpl): CredentialInteractor
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt
new file mode 100644
index 000000000000..55a2d3d7563e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.biometrics.domain.interactor
+
+import android.app.ActivityTaskManager
+import com.android.systemui.biometrics.data.repository.BiometricStatusRepository
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** Encapsulates business logic for interacting with biometric authentication state. */
+interface BiometricStatusInteractor {
+ /**
+ * The logical reason for the current side fingerprint sensor auth operation if one is on-going,
+ * filtered for when the overlay should be shown, otherwise [NotRunning].
+ */
+ val sfpsAuthenticationReason: Flow<AuthenticationReason>
+}
+
+class BiometricStatusInteractorImpl
+@Inject
+constructor(
+ private val activityTaskManager: ActivityTaskManager,
+ biometricStatusRepository: BiometricStatusRepository,
+) : BiometricStatusInteractor {
+
+ override val sfpsAuthenticationReason: Flow<AuthenticationReason> =
+ biometricStatusRepository.fingerprintAuthenticationReason.map { reason: AuthenticationReason
+ ->
+ if (reason.isReasonToAlwaysUpdateSfpsOverlay(activityTaskManager)) {
+ reason
+ } else {
+ AuthenticationReason.NotRunning
+ }
+ }
+
+ companion object {
+ private const val TAG = "BiometricStatusInteractor"
+ }
+}
+
+/** True if the sfps overlay should always be updated for this request source, false otherwise. */
+private fun AuthenticationReason.isReasonToAlwaysUpdateSfpsOverlay(
+ activityTaskManager: ActivityTaskManager
+): Boolean =
+ when (this) {
+ AuthenticationReason.DeviceEntryAuthentication -> false
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER) ->
+ when (activityTaskManager.topClass()) {
+ // TODO(b/186176653): exclude fingerprint overlays from this list view
+ "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false
+ else -> true
+ }
+ else -> true
+ }
+
+internal fun ActivityTaskManager.topClass(): String =
+ getTasks(1).firstOrNull()?.topActivity?.className ?: ""
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
index f51379940640..f4231ac01fee 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
@@ -141,7 +141,6 @@ constructor(
}
}
}
-
SideFpsSensorLocation(
left = sensorLeft,
top = sensorTop,
@@ -149,7 +148,15 @@ constructor(
isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation
)
}
- .distinctUntilChanged()
+ .distinctUntilChanged(
+ areEquivalent = { old: SideFpsSensorLocation, new: SideFpsSensorLocation ->
+ old.left == new.left &&
+ old.top == new.top &&
+ old.length == new.length &&
+ old.isSensorVerticalInDefaultOrientation ==
+ new.isSensorVerticalInDefaultOrientation
+ }
+ )
.onEach {
logger.sensorLocationStateChanged(
it.left,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt
new file mode 100644
index 000000000000..899b07e89964
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.biometrics.shared
+
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+import com.android.systemui.shared.Flags
+
+/** Helper for reading or using the sidefps controller refactor flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object SideFpsControllerRefactor {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.sidefpsControllerRefactor()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt
new file mode 100644
index 000000000000..0c3debbe0fc4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.biometrics.shared.model
+
+/**
+ * The logical reason for a fingerprint auth operation if one is on-going, otherwise [NotRunning].
+ */
+sealed interface AuthenticationReason {
+ /** Device entry requested authentication */
+ data object DeviceEntryAuthentication : AuthenticationReason
+
+ /** Settings requested authentication */
+ data class SettingsAuthentication(val settingsOperation: SettingsOperations) :
+ AuthenticationReason
+
+ /** App requested authentication */
+ data object BiometricPromptAuthentication : AuthenticationReason
+
+ /** Authentication requested for other reason */
+ data object OtherAuthentication : AuthenticationReason
+
+ /** Authentication requested for unknown reason */
+ data object Unknown : AuthenticationReason
+
+ /** Authentication is not running */
+ data object NotRunning : AuthenticationReason
+
+ /** Settings operations that request biometric authentication */
+ enum class SettingsOperations {
+ ENROLL_ENROLLING,
+ ENROLL_FIND_SENSOR,
+ OTHER
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt
new file mode 100644
index 000000000000..0b3005530e6d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.biometrics.shared.model
+
+import com.airbnb.lottie.model.KeyPath
+
+/** Represents properties of a LottieAnimationView callback */
+data class LottieCallback(val keypath: KeyPath, val color: Int)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 32d9067bd9e4..90e4a3821634 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -376,6 +376,22 @@ object BiometricViewBinder {
}
}
+ // Talkback directional guidance
+ backgroundView.setOnHoverListener { _, event ->
+ launch {
+ viewModel.onAnnounceAccessibilityHint(
+ event,
+ accessibilityManager.isTouchExplorationEnabled
+ )
+ }
+ false
+ }
+ launch {
+ viewModel.accessibilityHint.collect { message ->
+ if (message.isNotBlank()) view.announceForAccessibility(message)
+ }
+ }
+
// Play haptics
launch {
viewModel.hapticsToPlay.collect { hapticFeedbackConstant ->
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
new file mode 100644
index 000000000000..a8c9446fd689
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
@@ -0,0 +1,224 @@
+/*
+ * 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.biometrics.ui.binder
+
+import android.content.Context
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import android.view.LayoutInflater
+import android.view.View
+import android.view.WindowManager
+import android.view.accessibility.AccessibilityEvent
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.airbnb.lottie.LottieAnimationView
+import com.airbnb.lottie.LottieComposition
+import com.airbnb.lottie.LottieProperty
+import com.android.app.animation.Interpolators
+import com.android.keyguard.KeyguardPINView
+import com.android.systemui.CoreStartable
+import com.android.systemui.biometrics.FpsUnlockTracker
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.NotRunning
+import com.android.systemui.biometrics.shared.model.LottieCallback
+import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.launch
+
+/** Binds the side fingerprint sensor indicator view to [SideFpsOverlayViewModel]. */
+@SysUISingleton
+class SideFpsOverlayViewBinder
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ @Application private val applicationContext: Context,
+ private val biometricStatusInteractor: BiometricStatusInteractor,
+ private val displayStateInteractor: DisplayStateInteractor,
+ private val deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor,
+ private val fpsUnlockTracker: FpsUnlockTracker,
+ private val layoutInflater: LayoutInflater,
+ private val sideFpsProgressBarViewModel: SideFpsProgressBarViewModel,
+ private val sfpsSensorInteractor: SideFpsSensorInteractor,
+ private val windowManager: WindowManager
+) : CoreStartable {
+
+ override fun start() {
+ if (!SideFpsControllerRefactor.isEnabled) {
+ return
+ }
+ applicationScope
+ .launch {
+ combine(
+ biometricStatusInteractor.sfpsAuthenticationReason,
+ deviceEntrySideFpsOverlayInteractor.showIndicatorForDeviceEntry,
+ sideFpsProgressBarViewModel.isVisible,
+ ::Triple
+ )
+ .sample(displayStateInteractor.isInRearDisplayMode, ::Pair)
+ .collect { (combinedFlows, isInRearDisplayMode: Boolean) ->
+ val (
+ systemServerAuthReason,
+ showIndicatorForDeviceEntry,
+ progressBarIsVisible) =
+ combinedFlows
+ if (!isInRearDisplayMode) {
+ if (progressBarIsVisible) {
+ hide()
+ } else if (systemServerAuthReason != NotRunning) {
+ show()
+ } else if (showIndicatorForDeviceEntry) {
+ show()
+ } else {
+ hide()
+ }
+ }
+ }
+ }
+ .invokeOnCompletion { fpsUnlockTracker.stopTracking() }
+ }
+
+ private var overlayView: View? = null
+ private var lottie: LottieAnimationView? = null
+
+ /** Show the side fingerprint sensor indicator */
+ private fun show() {
+ overlayView?.let {
+ if (it.isAttachedToWindow) {
+ lottie = it.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
+ lottie?.pauseAnimation()
+ windowManager.removeView(it)
+ }
+ }
+
+ overlayView = layoutInflater.inflate(R.layout.sidefps_view, null, false)
+ val overlayViewModel =
+ SideFpsOverlayViewModel(
+ applicationContext,
+ biometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor,
+ sfpsSensorInteractor,
+ sideFpsProgressBarViewModel
+ )
+ bind(overlayView!!, overlayViewModel, fpsUnlockTracker, windowManager)
+ overlayView!!.visibility = View.INVISIBLE
+ windowManager.addView(overlayView, overlayViewModel.defaultOverlayViewParams)
+ }
+
+ /** Hide the side fingerprint sensor indicator */
+ private fun hide() {
+ if (overlayView != null) {
+ windowManager.removeView(overlayView)
+ overlayView = null
+ }
+ }
+
+ companion object {
+ private const val TAG = "SideFpsOverlayViewBinder"
+
+ /** Binds overlayView (side fingerprint sensor indicator view) to SideFpsOverlayViewModel */
+ fun bind(
+ overlayView: View,
+ viewModel: SideFpsOverlayViewModel,
+ fpsUnlockTracker: FpsUnlockTracker,
+ windowManager: WindowManager
+ ) {
+ overlayView.repeatWhenAttached {
+ fpsUnlockTracker.startTracking()
+
+ val lottie = it.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
+ lottie.addLottieOnCompositionLoadedListener { composition: LottieComposition ->
+ viewModel.setLottieBounds(composition.bounds)
+ overlayView.visibility = View.VISIBLE
+ }
+ it.alpha = 0f
+ val overlayShowAnimator =
+ it.animate()
+ .alpha(1f)
+ .setDuration(KeyguardPINView.ANIMATION_DURATION)
+ .setInterpolator(Interpolators.ALPHA_IN)
+
+ overlayShowAnimator.start()
+
+ it.setAccessibilityDelegate(
+ object : View.AccessibilityDelegate() {
+ override fun dispatchPopulateAccessibilityEvent(
+ host: View,
+ event: AccessibilityEvent
+ ): Boolean {
+ return if (
+ event.getEventType() ===
+ android.view.accessibility.AccessibilityEvent
+ .TYPE_WINDOW_STATE_CHANGED
+ ) {
+ true
+ } else {
+ super.dispatchPopulateAccessibilityEvent(host, event)
+ }
+ }
+ }
+ )
+
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.lottieCallbacks.collect { callbacks ->
+ lottie.addOverlayDynamicColor(callbacks)
+ }
+ }
+
+ launch {
+ viewModel.overlayViewParams.collect { params ->
+ windowManager.updateViewLayout(it, params)
+ lottie.resumeAnimation()
+ }
+ }
+
+ launch {
+ viewModel.overlayViewProperties.collect { properties ->
+ it.rotation = properties.overlayViewRotation
+ lottie.setAnimation(properties.indicatorAsset)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+private fun LottieAnimationView.addOverlayDynamicColor(colorCallbacks: List<LottieCallback>) {
+ addLottieOnCompositionLoadedListener {
+ for (callback in colorCallbacks) {
+ addValueCallback(callback.keypath, LottieProperty.COLOR_FILTER) {
+ PorterDuffColorFilter(callback.color, PorterDuff.Mode.SRC_ATOP)
+ }
+ }
+ resumeAnimation()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 647aaf392ed8..6d0a58e202bd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -21,9 +21,12 @@ import android.hardware.biometrics.BiometricPrompt
import android.util.Log
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
+import com.android.systemui.Flags.bpTalkback
+import com.android.systemui.biometrics.UdfpsUtils
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricModality
import com.android.systemui.biometrics.shared.model.DisplayRotation
@@ -35,7 +38,9 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -49,7 +54,9 @@ class PromptViewModel
constructor(
displayStateInteractor: DisplayStateInteractor,
promptSelectorInteractor: PromptSelectorInteractor,
- @Application context: Context,
+ @Application private val context: Context,
+ private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
+ private val udfpsUtils: UdfpsUtils
) {
/** The set of modalities available for this prompt */
val modalities: Flow<BiometricModalities> =
@@ -69,6 +76,11 @@ constructor(
val faceIconHeight: Int =
context.resources.getDimensionPixelSize(R.dimen.biometric_dialog_face_icon_size)
+ private val _accessibilityHint = MutableSharedFlow<String>()
+
+ /** Hint for talkback directional guidance */
+ val accessibilityHint: Flow<String> = _accessibilityHint.asSharedFlow()
+
private val _isAuthenticating: MutableStateFlow<Boolean> = MutableStateFlow(false)
/** If the user is currently authenticating (i.e. at least one biometric is scanning). */
@@ -516,6 +528,40 @@ constructor(
return false
}
+ /** Sets the message used for UDFPS directional guidance */
+ suspend fun onAnnounceAccessibilityHint(
+ event: MotionEvent,
+ touchExplorationEnabled: Boolean,
+ ): Boolean {
+ if (bpTalkback() && modalities.first().hasUdfps && touchExplorationEnabled) {
+ // TODO(b/315184924): Remove uses of UdfpsUtils
+ val scaledTouch =
+ udfpsUtils.getTouchInNativeCoordinates(
+ event.getPointerId(0),
+ event,
+ udfpsOverlayInteractor.udfpsOverlayParams.value
+ )
+ if (
+ !udfpsUtils.isWithinSensorArea(
+ event.getPointerId(0),
+ event,
+ udfpsOverlayInteractor.udfpsOverlayParams.value
+ )
+ ) {
+ _accessibilityHint.emit(
+ udfpsUtils.onTouchOutsideOfSensorArea(
+ touchExplorationEnabled,
+ context,
+ scaledTouch.x,
+ scaledTouch.y,
+ udfpsOverlayInteractor.udfpsOverlayParams.value
+ )
+ )
+ }
+ }
+ return false
+ }
+
/**
* Switch to the credential view.
*
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
new file mode 100644
index 000000000000..ce726034913f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
@@ -0,0 +1,229 @@
+/*
+ * 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.biometrics.ui.viewmodel
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Color
+import android.graphics.PixelFormat
+import android.graphics.Point
+import android.graphics.Rect
+import android.view.Gravity
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
+import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
+import com.airbnb.lottie.model.KeyPath
+import com.android.systemui.biometrics.Utils
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.domain.model.SideFpsSensorLocation
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.biometrics.shared.model.LottieCallback
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+
+/** Models UI of the side fingerprint sensor indicator view. */
+class SideFpsOverlayViewModel
+@Inject
+constructor(
+ @Application private val applicationContext: Context,
+ biometricStatusInteractor: BiometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor: DisplayStateInteractor,
+ sfpsSensorInteractor: SideFpsSensorInteractor,
+ sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
+) {
+ /** Contains properties of the side fingerprint sensor indicator */
+ data class OverlayViewProperties(
+ /** The raw asset for the indicator animation */
+ val indicatorAsset: Int,
+ /** Rotation of the overlayView */
+ val overlayViewRotation: Float,
+ )
+
+ private val _lottieBounds: MutableStateFlow<Rect?> = MutableStateFlow(null)
+
+ /** Used for setting lottie bounds once the composition has loaded. */
+ fun setLottieBounds(bounds: Rect) {
+ _lottieBounds.value = bounds
+ }
+
+ private val displayRotation = displayStateInteractor.currentRotation
+ private val sensorLocation = sfpsSensorInteractor.sensorLocation
+
+ /** Default LayoutParams for the overlayView */
+ val defaultOverlayViewParams: WindowManager.LayoutParams
+ get() =
+ WindowManager.LayoutParams(
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS,
+ PixelFormat.TRANSLUCENT
+ )
+ .apply {
+ title = TAG
+ fitInsetsTypes = 0 // overrides default, avoiding status bars during layout
+ gravity = Gravity.TOP or Gravity.LEFT
+ layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ privateFlags = PRIVATE_FLAG_TRUSTED_OVERLAY or PRIVATE_FLAG_NO_MOVE_ANIMATION
+ }
+
+ private val indicatorAsset: Flow<Int> =
+ combine(displayRotation, sensorLocation) { rotation: DisplayRotation, sensorLocation ->
+ val yAligned = sensorLocation.isSensorVerticalInDefaultOrientation
+ val newAsset: Int =
+ when (rotation) {
+ DisplayRotation.ROTATION_0 ->
+ if (yAligned) {
+ R.raw.sfps_pulse
+ } else {
+ R.raw.sfps_pulse_landscape
+ }
+ DisplayRotation.ROTATION_180 ->
+ if (yAligned) {
+ R.raw.sfps_pulse
+ } else {
+ R.raw.sfps_pulse_landscape
+ }
+ else ->
+ if (yAligned) {
+ R.raw.sfps_pulse_landscape
+ } else {
+ R.raw.sfps_pulse
+ }
+ }
+ newAsset
+ }
+ .distinctUntilChanged()
+
+ private val overlayViewRotation: Flow<Float> =
+ combine(
+ displayRotation,
+ sensorLocation,
+ ) { rotation: DisplayRotation, sensorLocation ->
+ val yAligned = sensorLocation.isSensorVerticalInDefaultOrientation
+ when (rotation) {
+ DisplayRotation.ROTATION_90 -> if (yAligned) 0f else 180f
+ DisplayRotation.ROTATION_180 -> 180f
+ DisplayRotation.ROTATION_270 -> if (yAligned) 180f else 0f
+ else -> 0f
+ }
+ }
+ .distinctUntilChanged()
+
+ /** Contains properties (animation asset and view rotation) for overlayView */
+ val overlayViewProperties: Flow<OverlayViewProperties> =
+ combine(indicatorAsset, overlayViewRotation) { asset: Int, rotation: Float ->
+ OverlayViewProperties(asset, rotation)
+ }
+
+ /** LayoutParams for placement of overlayView (the side fingerprint sensor indicator view) */
+ val overlayViewParams: Flow<WindowManager.LayoutParams> =
+ combine(
+ _lottieBounds,
+ sensorLocation,
+ displayRotation,
+ ) { bounds: Rect?, sensorLocation: SideFpsSensorLocation, displayRotation: DisplayRotation
+ ->
+ val topLeft = Point(sensorLocation.left, sensorLocation.top)
+
+ if (sensorLocation.isSensorVerticalInDefaultOrientation) {
+ if (displayRotation == DisplayRotation.ROTATION_0) {
+ topLeft.x -= bounds!!.width()
+ } else if (displayRotation == DisplayRotation.ROTATION_270) {
+ topLeft.y -= bounds!!.height()
+ }
+ } else {
+ if (displayRotation == DisplayRotation.ROTATION_180) {
+ topLeft.y -= bounds!!.height()
+ } else if (displayRotation == DisplayRotation.ROTATION_270) {
+ topLeft.x -= bounds!!.width()
+ }
+ }
+ defaultOverlayViewParams.apply {
+ x = topLeft.x
+ y = topLeft.y
+ }
+ }
+
+ /** List of LottieCallbacks use for adding dynamic color to the overlayView */
+ val lottieCallbacks: Flow<List<LottieCallback>> =
+ combine(
+ biometricStatusInteractor.sfpsAuthenticationReason,
+ deviceEntrySideFpsOverlayInteractor.showIndicatorForDeviceEntry.distinctUntilChanged(),
+ sideFpsProgressBarViewModel.isVisible,
+ ) { reason: AuthenticationReason, showIndicatorForDeviceEntry: Boolean, progressBarIsVisible
+ ->
+ val callbacks = mutableListOf<LottieCallback>()
+ if (showIndicatorForDeviceEntry) {
+ val indicatorColor =
+ com.android.settingslib.Utils.getColorAttrDefaultColor(
+ applicationContext,
+ com.android.internal.R.attr.materialColorPrimaryFixed
+ )
+ val outerRimColor =
+ com.android.settingslib.Utils.getColorAttrDefaultColor(
+ applicationContext,
+ com.android.internal.R.attr.materialColorPrimaryFixedDim
+ )
+ val chevronFill =
+ com.android.settingslib.Utils.getColorAttrDefaultColor(
+ applicationContext,
+ com.android.internal.R.attr.materialColorOnPrimaryFixed
+ )
+ callbacks.add(LottieCallback(KeyPath(".blue600", "**"), indicatorColor))
+ callbacks.add(LottieCallback(KeyPath(".blue400", "**"), outerRimColor))
+ callbacks.add(LottieCallback(KeyPath(".black", "**"), chevronFill))
+ } else {
+ if (!isDarkMode(applicationContext)) {
+ callbacks.add(LottieCallback(KeyPath(".black", "**"), Color.WHITE))
+ }
+ for (key in listOf(".blue600", ".blue400")) {
+ callbacks.add(
+ LottieCallback(
+ KeyPath(key, "**"),
+ applicationContext.getColor(
+ com.android.settingslib.color.R.color.settingslib_color_blue400
+ ),
+ )
+ )
+ }
+ }
+ callbacks
+ }
+
+ companion object {
+ private const val TAG = "SideFpsOverlayViewModel"
+ }
+}
+
+private fun isDarkMode(context: Context): Boolean {
+ val darkMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+ return darkMode == Configuration.UI_MODE_NIGHT_YES
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
index 1e0e16c5472f..c2a1d8fe26c3 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
@@ -18,6 +18,7 @@ package com.android.systemui.bouncer.data.repository
import android.os.Build
import android.util.Log
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import com.android.systemui.dagger.SysUISingleton
@@ -121,6 +122,7 @@ interface KeyguardBouncerRepository {
fun setAlternateBouncerUIAvailable(isAvailable: Boolean)
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
fun setSideFpsShowing(isShowing: Boolean)
}
@@ -261,7 +263,9 @@ constructor(
_isBackButtonEnabled.value = isBackButtonEnabled
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
override fun setSideFpsShowing(isShowing: Boolean) {
+ SideFpsControllerRefactor.assertInLegacyMode()
_sideFpsShowing.value = isShowing
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index aa7758f9380f..621ca5dc6f5a 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -28,6 +28,7 @@ import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.DejankUtils
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
@@ -116,9 +117,11 @@ constructor(
/** Allow for interaction when just about fully visible */
val isInteractable: Flow<Boolean> = bouncerExpansion.map { it > 0.9 }
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
val sideFpsShowing: Flow<Boolean> = repository.sideFpsShowing
private var currentUserActiveUnlockRunning = false
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** This callback needs to be a class field so it does not get garbage collected. */
val keyguardUpdateMonitorCallback =
object : KeyguardUpdateMonitorCallback() {
@@ -135,7 +138,10 @@ constructor(
}
init {
- keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ if (!SideFpsControllerRefactor.isEnabled) {
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ }
applicationScope.launch {
trustRepository.isCurrentUserActiveUnlockRunning.collect {
currentUserActiveUnlockRunning = it
@@ -333,8 +339,10 @@ constructor(
repository.setPrimaryStartDisappearAnimation(runnable)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** Determine whether to show the side fps animation. */
fun updateSideFpsVisibility() {
+ SideFpsControllerRefactor.assertInLegacyMode()
val sfpsEnabled: Boolean =
context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
val fpsDetectionRunning: Boolean = keyguardUpdateMonitor.isFingerprintDetectionRunning
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 ac3d4b6c853b..5dcd6615509d 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
@@ -27,6 +27,7 @@ import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityView
import com.android.keyguard.dagger.KeyguardBouncerComponent
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.bouncer.ui.BouncerViewDelegate
@@ -233,15 +234,21 @@ object KeyguardBouncerViewBinder {
.collect { view.systemUiVisibility = it }
}
- launch {
- viewModel.shouldUpdateSideFps.collect {
- viewModel.updateSideFpsVisibility()
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ if (!SideFpsControllerRefactor.isEnabled) {
+ launch {
+ viewModel.shouldUpdateSideFps.collect {
+ viewModel.updateSideFpsVisibility()
+ }
}
}
- launch {
- viewModel.sideFpsShowing.collect {
- securityContainerController.updateSideFpsVisibility(it)
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ if (!SideFpsControllerRefactor.isEnabled) {
+ launch {
+ viewModel.sideFpsShowing.collect {
+ securityContainerController.updateSideFpsVisibility(it)
+ }
}
}
awaitCancellation()
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
index 649ae2fb1007..1c9d1f01e89e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.bouncer.ui.viewmodel
import android.view.View
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import com.android.systemui.bouncer.ui.BouncerView
@@ -61,9 +62,11 @@ constructor(
/** Observe whether keyguard is authenticated already. */
val keyguardAuthenticated: Flow<Boolean> = interactor.keyguardAuthenticatedBiometrics
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** Observe whether the side fps is showing. */
val sideFpsShowing: Flow<Boolean> = interactor.sideFpsShowing
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** Observe whether we should update fps is showing. */
val shouldUpdateSideFps: Flow<Unit> =
merge(
@@ -87,7 +90,9 @@ constructor(
interactor.onMessageShown()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
fun updateSideFpsVisibility() {
+ SideFpsControllerRefactor.assertInLegacyMode()
interactor.updateSideFpsVisibility()
}
diff --git a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
index 7ac1cc796d4b..9d4ed20ca582 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
@@ -25,11 +25,15 @@ import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
+import androidx.annotation.Nullable;
+
import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.Utils;
import com.android.systemui.CoreStartable;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent;
@@ -43,6 +47,7 @@ import com.android.systemui.dagger.qualifiers.SystemUser;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.condition.ConditionalCoreStartable;
@@ -195,34 +200,70 @@ public class DreamHomeControlsComplication implements Complication {
private final ActivityStarter mActivityStarter;
private final Context mContext;
+ private final ConfigurationController mConfigurationController;
private final ControlsComponent mControlsComponent;
private final UiEventLogger mUiEventLogger;
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onUiModeChanged() {
+ reloadResources();
+ }
+ };
+
@Inject
DreamHomeControlsChipViewController(
@Named(DREAM_HOME_CONTROLS_CHIP_VIEW) ImageView view,
ActivityStarter activityStarter,
Context context,
+ ConfigurationController configurationController,
ControlsComponent controlsComponent,
UiEventLogger uiEventLogger) {
super(view);
mActivityStarter = activityStarter;
mContext = context;
+ mConfigurationController = configurationController;
mControlsComponent = controlsComponent;
mUiEventLogger = uiEventLogger;
}
@Override
protected void onViewAttached() {
- mView.setImageResource(mControlsComponent.getTileImageId());
- mView.setContentDescription(mContext.getString(mControlsComponent.getTileTitleId()));
+ reloadResources();
mView.setOnClickListener(this::onClickHomeControls);
+ mConfigurationController.addCallback(mConfigurationListener);
}
@Override
- protected void onViewDetached() {}
+ protected void onViewDetached() {
+ mConfigurationController.removeCallback(mConfigurationListener);
+ }
+
+ private void reloadResources() {
+ final String title = getControlsTitle();
+ if (title != null) {
+ mView.setContentDescription(title);
+ }
+ mView.setImageResource(mControlsComponent.getTileImageId());
+ mView.setImageTintList(Utils.getColorAttr(mContext, android.R.attr.textColorPrimary));
+ final Drawable background = mView.getBackground();
+ if (background != null) {
+ background.setTintList(
+ Utils.getColorAttr(mContext, com.android.internal.R.attr.colorSurface));
+ }
+ }
+
+ @Nullable
+ private String getControlsTitle() {
+ try {
+ return mContext.getString(mControlsComponent.getTileTitleId());
+ } catch (Resources.NotFoundException e) {
+ return null;
+ }
+ }
private void onClickHomeControls(View v) {
if (DEBUG) Log.d(TAG, "home controls complication tapped");
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
index 08d0595eba23..b6dcfcbfad56 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
@@ -24,9 +24,8 @@ import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.widget.ImageView;
-import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
import com.android.systemui.complication.DreamHomeControlsComplication;
+import com.android.systemui.res.R;
import com.android.systemui.shared.shadow.DoubleShadowIconDrawable;
import com.android.systemui.shared.shadow.DoubleShadowTextHelper;
@@ -98,7 +97,7 @@ public interface DreamHomeControlsComplicationComponent {
@DreamHomeControlsComplicationScope
@Named(DREAM_HOME_CONTROLS_BACKGROUND_DRAWABLE)
static Drawable providesHomeControlsBackground(Context context, Resources resources) {
- final Drawable background = new DoubleShadowIconDrawable(createShadowInfo(
+ return new DoubleShadowIconDrawable(createShadowInfo(
resources,
R.dimen.dream_overlay_bottom_affordance_key_text_shadow_radius,
R.dimen.dream_overlay_bottom_affordance_key_text_shadow_dx,
@@ -117,11 +116,6 @@ public interface DreamHomeControlsComplicationComponent {
R.dimen.dream_overlay_bottom_affordance_width),
resources.getDimensionPixelSize(R.dimen.dream_overlay_bottom_affordance_inset)
);
-
- background.setTintList(
- Utils.getColorAttr(context, com.android.internal.R.attr.colorSurface));
-
- return background;
}
private static DoubleShadowTextHelper.ShadowInfo createShadowInfo(Resources resources,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt
index ae3b501d3006..e96660fe4f79 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt
@@ -25,7 +25,7 @@ import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.Compile
import com.android.systemui.util.asIndenting
-import com.android.systemui.util.withIncreasedIndent
+import com.android.systemui.util.printCollection
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
@@ -59,10 +59,8 @@ abstract class FlagDependenciesBase(
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.asIndenting().run {
- println("allDependencies: ${allDependencies.size}")
- withIncreasedIndent { allDependencies.forEach(::println) }
- println("unmetDependencies: ${unmetDependencies.size}")
- withIncreasedIndent { unmetDependencies.forEach(::println) }
+ printCollection("allDependencies", allDependencies)
+ printCollection("unmetDependencies", unmetDependencies)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
index ae67e60b75f7..4d89a826b60a 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
@@ -79,6 +79,22 @@ object RefactorFlagUtils {
check(!isEnabled) { "Legacy code path not supported when $flagName is enabled." }
/**
+ * Called to ensure the new code is only run when the flag is enabled. This will throw an
+ * exception if the flag is disabled to ensure that the refactor author catches issues in
+ * testing.
+ *
+ * Example usage:
+ * ```
+ * public void setSomeNewController(SomeController someController) {
+ * SomeRefactor.assertInNewMode();
+ * mSomeController = someController;
+ * }
+ * ````
+ */
+ inline fun assertInNewMode(isEnabled: Boolean, flagName: Any) =
+ check(isEnabled) { "New code path not supported when $flagName is disabled." }
+
+ /**
* This will [Log.wtf] with the given message, assuming [ASSERT_TAG] is loggable at that level.
* This means an engineer can prevent this from crashing by running the command:
* ```
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 33dd3d9bea16..edf964815ca1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -35,7 +35,7 @@ import static android.view.WindowManager.TransitionFlags;
import static android.view.WindowManager.TransitionOldType;
import static android.view.WindowManager.TransitionType;
-import static com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER;
+import static com.android.systemui.Flags.refactorGetCurrentUser;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -609,7 +609,7 @@ public class KeyguardService extends Service {
public void setCurrentUser(int userId) {
trace("Deprecated/NOT USED: setCurrentUser userId=" + userId);
checkPermission();
- if (!mFlags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ if (!refactorGetCurrentUser()) {
mKeyguardViewMediator.setCurrentUser(userId);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 57f3b7071d1d..d7a1906f68e4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -38,7 +38,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER;
+import static com.android.systemui.Flags.refactorGetCurrentUser;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -617,7 +617,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
public void onUserSwitching(int userId) {
if (DEBUG) Log.d(TAG, String.format("onUserSwitching %d", userId));
synchronized (KeyguardViewMediator.this) {
- if (mFeatureFlags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ if (refactorGetCurrentUser()) {
notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
}
resetKeyguardDonePendingLocked();
@@ -1502,7 +1502,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- if (!mFeatureFlags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ if (!refactorGetCurrentUser()) {
KeyguardUpdateMonitor.setCurrentUser(mUserTracker.getUserId());
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
index 96386f3dc596..9a13558d3327 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
@@ -41,6 +41,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
/** Encapsulates state about device entry fingerprint auth mechanism. */
@@ -61,6 +62,9 @@ interface DeviceEntryFingerprintAuthRepository {
/** Provide the current status of fingerprint authentication. */
val authenticationStatus: Flow<FingerprintAuthenticationStatus>
+
+ /** Indicates whether to update the side fingerprint sensor indicator visibility. */
+ val shouldUpdateIndicatorVisibility: Flow<Boolean>
}
/**
@@ -256,6 +260,37 @@ constructor(
awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
+ override val shouldUpdateIndicatorVisibility: Flow<Boolean> =
+ conflatedCallbackFlow {
+ val sendShouldUpdateIndicatorVisibility =
+ { shouldUpdateIndicatorVisibility: Boolean ->
+ trySendWithFailureLogging(
+ shouldUpdateIndicatorVisibility,
+ TAG,
+ "Error sending shouldUpdateIndicatorVisibility " +
+ "$shouldUpdateIndicatorVisibility"
+ )
+ }
+
+ val callback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricRunningStateChanged(
+ running: Boolean,
+ biometricSourceType: BiometricSourceType?
+ ) {
+ sendShouldUpdateIndicatorVisibility(true)
+ }
+ override fun onStrongAuthStateChanged(userId: Int) {
+ sendShouldUpdateIndicatorVisibility(true)
+ }
+ }
+ sendShouldUpdateIndicatorVisibility(false)
+ keyguardUpdateMonitor.registerCallback(callback)
+ awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
+ }
+ .flowOn(mainDispatcher)
+ .shareIn(scope, started = SharingStarted.WhileSubscribed(), replay = 1)
+
companion object {
const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
new file mode 100644
index 000000000000..de15fd6a958f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
@@ -0,0 +1,92 @@
+/*
+ * 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 android.content.Context
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/**
+ * Encapsulates business logic for device entry events that impact the side fingerprint sensor
+ * overlay.
+ */
+@SysUISingleton
+class DeviceEntrySideFpsOverlayInteractor
+@Inject
+constructor(
+ @Application private val context: Context,
+ deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
+ private val primaryBouncerInteractor: PrimaryBouncerInteractor,
+ alternateBouncerInteractor: AlternateBouncerInteractor,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+) {
+
+ init {
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, TAG)
+ }
+
+ private val showIndicatorForPrimaryBouncer: Flow<Boolean> =
+ merge(
+ primaryBouncerInteractor.isShowing,
+ primaryBouncerInteractor.startingToHide,
+ primaryBouncerInteractor.startingDisappearAnimation.filterNotNull(),
+ deviceEntryFingerprintAuthRepository.shouldUpdateIndicatorVisibility.filter { it }
+ )
+ .map { shouldShowIndicatorForPrimaryBouncer() }
+
+ private val showIndicatorForAlternateBouncer: Flow<Boolean> =
+ alternateBouncerInteractor.isVisible
+
+ /**
+ * Indicates whether the primary or alternate bouncers request showing the side fingerprint
+ * sensor indicator.
+ */
+ val showIndicatorForDeviceEntry: Flow<Boolean> =
+ combine(showIndicatorForPrimaryBouncer, showIndicatorForAlternateBouncer) {
+ showForPrimaryBouncer,
+ showForAlternateBouncer ->
+ showForPrimaryBouncer || showForAlternateBouncer
+ }
+
+ private fun shouldShowIndicatorForPrimaryBouncer(): Boolean {
+ val sfpsEnabled: Boolean =
+ context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
+ val sfpsDetectionRunning = keyguardUpdateMonitor.isFingerprintDetectionRunning
+ val isUnlockingWithFpAllowed = keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed
+ return primaryBouncerInteractor.isBouncerShowing() &&
+ sfpsEnabled &&
+ sfpsDetectionRunning &&
+ isUnlockingWithFpAllowed &&
+ !primaryBouncerInteractor.isAnimatingAway()
+ }
+
+ companion object {
+ private const val TAG = "DeviceEntrySideFpsOverlayInteractor"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
index 560e4adf956a..9a6dca3c4958 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
@@ -21,6 +21,7 @@ import android.graphics.Point
import com.android.systemui.CoreStartable
import com.android.systemui.Flags
import com.android.systemui.biometrics.SideFpsController
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.ui.view.SideFpsProgressBar
@@ -46,6 +47,7 @@ constructor(
private val viewModel: SideFpsProgressBarViewModel,
private val view: SideFpsProgressBar,
@Application private val applicationScope: CoroutineScope,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
private val sfpsController: dagger.Lazy<SideFpsController>,
private val logger: SideFpsLogger,
private val commandRegistry: CommandRegistry,
@@ -109,12 +111,14 @@ constructor(
view.updateView(visible, location, length, thickness, rotation)
// We have to hide the SFPS indicator as the progress bar will
// be shown at the same location
- if (visible) {
- logger.hidingSfpsIndicator()
- sfpsController.get().hideIndicator()
- } else if (fpDetectRunning) {
- logger.showingSfpsIndicator()
- sfpsController.get().showIndicator()
+ if (!SideFpsControllerRefactor.isEnabled) {
+ if (visible) {
+ logger.hidingSfpsIndicator()
+ sfpsController.get().hideIndicator()
+ } else if (fpDetectRunning) {
+ logger.showingSfpsIndicator()
+ sfpsController.get().showIndicator()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
index 2d0712c7f9cc..1dbf1f14b569 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Point
+import androidx.annotation.VisibleForTesting
import androidx.core.animation.doOnEnd
import com.android.systemui.Flags
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
@@ -213,4 +214,9 @@ constructor(
}
}
}
+
+ @VisibleForTesting
+ fun setVisible(isVisible: Boolean) {
+ _visible.value = isVisible
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 9846f4b6c980..e660b97b5c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -69,7 +69,6 @@ import androidx.annotation.DimenRes;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.policy.GestureNavigationSettingsObserver;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
@@ -81,6 +80,7 @@ import com.android.systemui.plugins.NavigationEdgeBackPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputChannelCompat;
@@ -1113,6 +1113,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
// Capture inputs
mInputMonitor.pilferPointers();
if (mBackAnimation != null) {
+ mBackAnimation.onPilferPointers();
// Notify FalsingManager that an intentional gesture has occurred.
mFalsingManager.isFalseTouch(BACK_GESTURE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 270bfbe4274d..0e7e69b97d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -263,7 +263,11 @@ constructor(
* If the shortcut entry `android:enabled` is set to `true`, the shortcut will be visible in the
* Widget Picker to all users.
*/
+ // TODO(b/316332684)
+ @Suppress("UNREACHABLE_CODE")
fun setNoteTaskShortcutEnabled(value: Boolean, user: UserHandle) {
+ return // shortcut should not be enabled until additional features are implemented.
+
if (!userManager.isUserUnlocked(user)) {
debugLog { "setNoteTaskShortcutEnabled call but user locked: user=$user" }
return
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
index 6d55d0549d2e..de490a58a498 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
@@ -27,7 +27,6 @@ import android.os.UserManager
import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.res.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -43,6 +42,7 @@ import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEnabledKey
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskInfoResolver
+import com.android.systemui.res.R
import com.android.systemui.stylus.StylusManager
import dagger.Lazy
import java.util.concurrent.Executor
@@ -100,7 +100,8 @@ constructor(
isEnabled &&
isUserUnlocked &&
isDefaultNotesAppSet &&
- (isConfigSelected || isStylusEverUsed)
+ isConfigSelected &&
+ isStylusEverUsed
) {
val contentDescription = ContentDescription.Resource(pickerNameResourceId)
val icon = Icon.Resource(pickerIconResourceId, contentDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 6c930b1f3d17..3e50dd35749f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -43,6 +43,9 @@ import com.android.systemui.statusbar.policy.SplitShadeStateController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.animation.DisappearParameters;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
@@ -50,9 +53,6 @@ import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;
-import kotlin.Unit;
-import kotlin.jvm.functions.Function1;
-
/**
* Controller for QSPanel views.
*
@@ -232,7 +232,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
mQsTileRevealController.updateRevealedTiles(tiles);
}
boolean shouldChange = false;
- if (tiles.size() == mRecords.size()) {
+ if (tiles.size() <= mRecords.size()) {
int i = 0;
for (QSTile tile : tiles) {
if (tile != mRecords.get(i).tile) {
@@ -241,6 +241,17 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
}
i++;
}
+
+ // If the first tiles are the same as the new ones, remove any extras.
+ if (!shouldChange) {
+ while (i < mRecords.size()) {
+ QSPanelControllerBase.TileRecord record = mRecords.get(i);
+ mView.removeTile(record);
+ record.tile.removeCallback(record.callback);
+ i++;
+ }
+ mCachedSpecs = getTilesSpecs();
+ }
} else {
shouldChange = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
index 935d07229ae5..42bee3c8f877 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
@@ -22,8 +22,8 @@ class QSPipelineFlagsRepository @Inject constructor() {
AconfigFlags.FLAG_QS_NEW_PIPELINE
)
- fun assertNewTilesInLegacyMode() =
- RefactorFlagUtils.assertInLegacyMode(
+ fun assertNewTiles() =
+ RefactorFlagUtils.assertInNewMode(
AconfigFlags.qsNewTiles(),
AconfigFlags.FLAG_QS_NEW_TILES
)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 38bbce45e143..17e6375967fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -19,6 +19,7 @@ import android.util.Log;
import androidx.annotation.Nullable;
+import com.android.systemui.accessibility.qs.QSAccessibilityModule;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
@@ -41,7 +42,7 @@ import javax.inject.Provider;
* com.android.systemui.qs.tiles.DreamTile#TILE_SPEC})
*
* After, create or find an existing Module class to house the tile's binding method (e.g. {@link
- * com.android.systemui.accessibility.AccessibilityModule}). If creating a new module, add your
+ * QSAccessibilityModule}). If creating a new module, add your
* module to the SystemUI dagger graph by including it in an appropriate module.
*/
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index 0434b2d89e32..66da8bdd0311 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -42,6 +42,7 @@ import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.recordissue.RecordIssueDialogDelegate
import com.android.systemui.res.R
+import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -63,6 +64,7 @@ constructor(
private val keyguardStateController: KeyguardStateController,
private val dialogLaunchAnimator: DialogLaunchAnimator,
private val sysuiDialogFactory: SystemUIDialog.Factory,
+ private val userContextProvider: UserContextProvider,
) :
QSTileImpl<QSTile.BooleanState>(
host,
@@ -100,7 +102,7 @@ constructor(
private fun showPrompt(view: View?) {
val dialog: AlertDialog =
- RecordIssueDialogDelegate(sysuiDialogFactory) {
+ RecordIssueDialogDelegate(sysuiDialogFactory, userContextProvider) {
isRecording = true
refreshState()
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
new file mode 100644
index 000000000000..d0437a7210f1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
@@ -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.android.systemui.qs.tiles.base.viewmodel
+
+import com.android.systemui.dagger.qualifiers.Application
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+
+/** Creates a [CoroutineScope] for the [QSTileViewModelImpl]. */
+class QSTileCoroutineScopeFactory
+@Inject
+constructor(@Application private val applicationScope: CoroutineScope) {
+
+ fun create(): CoroutineScope =
+ CoroutineScope(applicationScope.coroutineContext + SupervisorJob())
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
index ae554d954580..ffa3b543736b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
@@ -82,6 +82,7 @@ sealed interface QSTileViewModelFactory<T> {
qsTileLogger,
systemClock,
backgroundDispatcher,
+ component.coroutineScope(),
)
}
}
@@ -101,6 +102,7 @@ sealed interface QSTileViewModelFactory<T> {
private val qsTileConfigProvider: QSTileConfigProvider,
private val systemClock: SystemClock,
@Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val coroutineScopeFactory: QSTileCoroutineScopeFactory,
) : QSTileViewModelFactory<T> {
/**
@@ -130,6 +132,7 @@ sealed interface QSTileViewModelFactory<T> {
qsTileLogger,
systemClock,
backgroundDispatcher,
+ coroutineScopeFactory.create(),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
index 9fe316f99136..45c6fffe6bd1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
@@ -39,7 +39,6 @@ import java.io.PrintWriter
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -82,7 +81,7 @@ class QSTileViewModelImpl<DATA_TYPE>(
private val qsTileLogger: QSTileLogger,
private val systemClock: SystemClock,
private val backgroundDispatcher: CoroutineDispatcher,
- private val tileScope: CoroutineScope = CoroutineScope(SupervisorJob()),
+ private val tileScope: CoroutineScope,
) : QSTileViewModel, Dumpable {
private val users: MutableStateFlow<UserHandle> =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
index 52e49f9d2653..382cfe267aae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
@@ -45,7 +45,7 @@ constructor(
) : QSFactory {
init {
- QSPipelineFlagsRepository.assertNewTilesInLegacyMode()
+ QSPipelineFlagsRepository.assertNewTiles()
for (viewModelTileSpec in tileMap.keys) {
require(qsTileConfigProvider.hasConfig(viewModelTileSpec)) {
"No config for $viewModelTileSpec"
@@ -56,7 +56,7 @@ constructor(
override fun createTile(tileSpec: String): QSTile? {
val viewModel: QSTileViewModel =
when (val spec = TileSpec.create(tileSpec)) {
- is TileSpec.CustomTileSpec -> createCustomTileViewModel(spec)
+ is TileSpec.CustomTileSpec -> null
is TileSpec.PlatformTileSpec -> tileMap[tileSpec]?.get()
is TileSpec.Invalid -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt
new file mode 100644
index 000000000000..1efbfd70fa98
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.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.systemui.qs.tiles.impl.colorcorrection.domain
+
+import android.content.res.Resources
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+/** Maps [ColorCorrectionTileModel] to [QSTileState]. */
+class ColorCorrectionTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Resources.Theme,
+) : QSTileDataToStateMapper<ColorCorrectionTileModel> {
+
+ override fun map(config: QSTileConfig, data: ColorCorrectionTileModel): QSTileState =
+ QSTileState.build(resources, theme, config.uiConfig) {
+ val subtitleArray = resources.getStringArray(R.array.tile_states_color_correction)
+
+ if (data.isEnabled) {
+ activationState = QSTileState.ActivationState.ACTIVE
+ secondaryLabel = subtitleArray[2]
+ } else {
+ activationState = QSTileState.ActivationState.INACTIVE
+ secondaryLabel = subtitleArray[1]
+ }
+ contentDescription = label
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt
new file mode 100644
index 000000000000..cd33d451ba81
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.os.UserHandle
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+/** Observes color correction state changes providing the [ColorCorrectionTileModel]. */
+class ColorCorrectionTileDataInteractor
+@Inject
+constructor(
+ private val colorCorrectionRepository: ColorCorrectionRepository,
+) : QSTileDataInteractor<ColorCorrectionTileModel> {
+
+ override fun tileData(
+ user: UserHandle,
+ triggers: Flow<DataUpdateTrigger>
+ ): Flow<ColorCorrectionTileModel> {
+ return colorCorrectionRepository.isEnabled(user).map { ColorCorrectionTileModel(it) }
+ }
+ override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt
new file mode 100644
index 000000000000..d1838029db4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.content.Intent
+import android.provider.Settings
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.interactor.QSTileInput
+import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import javax.inject.Inject
+
+/** Handles color correction tile clicks. */
+class ColorCorrectionUserActionInteractor
+@Inject
+constructor(
+ private val colorCorrectionRepository: ColorCorrectionRepository,
+ private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+) : QSTileUserActionInteractor<ColorCorrectionTileModel> {
+
+ override suspend fun handleInput(input: QSTileInput<ColorCorrectionTileModel>): Unit =
+ with(input) {
+ when (action) {
+ is QSTileUserAction.Click -> {
+ colorCorrectionRepository.setIsEnabled(
+ !data.isEnabled,
+ user,
+ )
+ }
+ is QSTileUserAction.LongClick -> {
+ qsTileIntentUserActionHandler.handle(
+ action.view,
+ Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+ )
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt
new file mode 100644
index 000000000000..66487e1bba60
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain.model
+
+/**
+ * Color correction tile model.
+ *
+ * @param isEnabled is true when the color correction is enabled;
+ */
+@JvmInline value class ColorCorrectionTileModel(val isEnabled: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
index 6d7d88fbfa79..92b0f3aa604d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
@@ -16,46 +16,103 @@
package com.android.systemui.qs.tiles.impl.custom.data.repository
+import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
import android.os.UserHandle
+import androidx.annotation.GuardedBy
import com.android.systemui.common.coroutine.ConflatedCallbackFlow
-import com.android.systemui.qs.external.TileServiceManager
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.android.systemui.qs.tiles.impl.custom.di.bound.CustomTileBoundScope
-import com.android.systemui.qs.tiles.impl.custom.di.bound.CustomTileUser
+import com.android.systemui.qs.tiles.impl.di.QSTileScope
import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.launch
interface CustomTilePackageUpdatesRepository {
- val packageChanges: Flow<Unit>
+ fun getPackageChangesForUser(user: UserHandle): Flow<Unit>
}
-@CustomTileBoundScope
+@QSTileScope
class CustomTilePackageUpdatesRepositoryImpl
@Inject
constructor(
- tileSpec: TileSpec.CustomTileSpec,
- @CustomTileUser user: UserHandle,
- serviceManager: TileServiceManager,
- defaultsRepository: CustomTileDefaultsRepository,
- @CustomTileBoundScope boundScope: CoroutineScope,
+ private val tileSpec: TileSpec.CustomTileSpec,
+ @Application private val context: Context,
+ @QSTileScope private val tileScope: CoroutineScope,
+ @Background private val backgroundCoroutineContext: CoroutineContext,
) : CustomTilePackageUpdatesRepository {
- override val packageChanges: Flow<Unit> =
+ @GuardedBy("perUserCache")
+ private val perUserCache: MutableMap<UserHandle, Flow<Unit>> = mutableMapOf()
+
+ override fun getPackageChangesForUser(user: UserHandle): Flow<Unit> =
+ synchronized(perUserCache) {
+ perUserCache.getOrPut(user) {
+ createPackageChangesFlowForUser(user)
+ .onCompletion {
+ // clear cache when nobody listens
+ synchronized(perUserCache) { perUserCache.remove(user) }
+ }
+ .flowOn(backgroundCoroutineContext)
+ .shareIn(tileScope, SharingStarted.WhileSubscribed())
+ }
+ }
+
+ @SuppressLint(
+ "MissingPermission", // android.permission.INTERACT_ACROSS_USERS_FULL
+ "UnspecifiedRegisterReceiverFlag",
+ "RegisterReceiverViaContext",
+ )
+ private fun createPackageChangesFlowForUser(user: UserHandle): Flow<Unit> =
ConflatedCallbackFlow.conflatedCallbackFlow {
- serviceManager.setTileChangeListener { changedComponentName ->
- if (changedComponentName == tileSpec.componentName) {
- trySend(Unit)
+ val receiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ launch { send(intent) }
+ }
}
+ context.registerReceiverAsUser(
+ receiver,
+ user,
+ INTENT_FILTER,
+ /* broadcastPermission = */ null,
+ /* scheduler = */ null,
+ )
+
+ awaitClose { context.unregisterReceiver(receiver) }
+ }
+ .filter { intent ->
+ intent ?: return@filter false
+ if (intent.action?.let(INTENT_FILTER::matchAction) != true) {
+ return@filter false
}
+ val changedComponentNames =
+ intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST)
+ changedComponentNames?.contains(tileSpec.componentName.packageName) == true
+ }
+ .map {}
+
+ private companion object {
+
+ val INTENT_FILTER =
+ IntentFilter().apply {
+ addDataScheme(IntentFilter.SCHEME_PACKAGE)
- awaitClose { serviceManager.setTileChangeListener(null) }
+ addAction(Intent.ACTION_PACKAGE_CHANGED)
}
- .onEach { defaultsRepository.requestNewDefaults(user, tileSpec.componentName, true) }
- .shareIn(boundScope, SharingStarted.WhileSubscribed())
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt
index d956fdebcd32..ba8b23ab795a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt
@@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles.impl.custom.di
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.base.viewmodel.QSTileCoroutineScopeFactory
import com.android.systemui.qs.tiles.impl.custom.CustomTileInteractor
import com.android.systemui.qs.tiles.impl.custom.CustomTileMapper
import com.android.systemui.qs.tiles.impl.custom.CustomTileUserActionInteractor
@@ -26,13 +27,15 @@ import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefau
import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefaultsRepositoryImpl
import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileRepository
import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileRepositoryImpl
-import com.android.systemui.qs.tiles.impl.custom.di.bound.CustomTileBoundComponent
import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel
+import com.android.systemui.qs.tiles.impl.di.QSTileScope
import dagger.Binds
import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.CoroutineScope
/** Provides bindings for QSTile interfaces */
-@Module(subcomponents = [CustomTileBoundComponent::class])
+@Module
interface CustomTileModule {
@Binds
@@ -54,4 +57,13 @@ interface CustomTileModule {
): CustomTileDefaultsRepository
@Binds fun bindCustomTileRepository(impl: CustomTileRepositoryImpl): CustomTileRepository
+
+ companion object {
+
+ @Provides
+ @QSTileScope
+ fun provideCustomTileCoroutineScope(
+ scopeFactory: QSTileCoroutineScopeFactory
+ ): CoroutineScope = scopeFactory.create()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt
index b3d916a86144..0ed46e73958d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt
@@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles.impl.di
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import kotlinx.coroutines.CoroutineScope
/**
* Base QS tile component. It should be used with [QSTileScope] to create a custom tile scoped
@@ -32,4 +33,12 @@ interface QSTileComponent<T> {
fun userActionInteractor(): QSTileUserActionInteractor<T>
fun dataToStateMapper(): QSTileDataToStateMapper<T>
+
+ /**
+ * Use [com.android.systemui.qs.tiles.base.viewmodel.QSTileCoroutineScopeFactory] to create a
+ * [CoroutineScope] provided by this method. This enables you to use the same scope the
+ * [com.android.systemui.qs.tiles.viewmodel.QSTileViewModel] uses. This scope is cancelled when
+ * the view model is destroyed.
+ */
+ @QSTileScope fun coroutineScope(): CoroutineScope
}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
index 8221c635741b..5bf44fa5b143 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -17,6 +17,9 @@
package com.android.systemui.recordissue
import android.annotation.SuppressLint
+import android.app.Activity
+import android.app.BroadcastOptions
+import android.app.PendingIntent
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
@@ -28,10 +31,14 @@ import android.widget.Button
import android.widget.PopupMenu
import android.widget.Switch
import com.android.systemui.res.R
+import com.android.systemui.screenrecord.RecordingService
+import com.android.systemui.screenrecord.ScreenRecordingAudioSource
+import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.phone.SystemUIDialog
class RecordIssueDialogDelegate(
private val factory: SystemUIDialog.Factory,
+ private val userContextProvider: UserContextProvider,
private val onStarted: Runnable
) : SystemUIDialog.Delegate {
@@ -46,6 +53,9 @@ class RecordIssueDialogDelegate(
setNegativeButton(R.string.cancel) { _, _ -> dismiss() }
setPositiveButton(R.string.qs_record_issue_start) { _, _ ->
onStarted.run()
+ if (screenRecordSwitch.isChecked) {
+ requestScreenCapture()
+ }
dismiss()
}
}
@@ -85,4 +95,19 @@ class RecordIssueDialogDelegate(
show()
}
}
+
+ private fun requestScreenCapture() =
+ PendingIntent.getForegroundService(
+ userContextProvider.userContext,
+ RecordingService.REQUEST_CODE,
+ RecordingService.getStartIntent(
+ userContextProvider.userContext,
+ Activity.RESULT_OK,
+ ScreenRecordingAudioSource.NONE.ordinal,
+ false,
+ null
+ ),
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ .send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
}
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 d42fde617394..47518bbee57a 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
@@ -44,6 +44,11 @@ import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICA
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.printSection
+import com.android.systemui.util.println
+import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -94,6 +99,15 @@ constructor(
}
}
+ override fun dump(pw: PrintWriter, args: Array<out String>) =
+ pw.asIndenting().run {
+ printSection("SceneContainerFlags") {
+ println("isEnabled", flags.isEnabled())
+ printSection("requirementDescription") { println(flags.requirementDescription()) }
+ println("flexiNotifsEnabled", flags.flexiNotifsEnabled())
+ }
+ }
+
/** Updates the visibility of the scene container. */
private fun hydrateVisibility() {
applicationScope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 886fa70d715d..2b9ad50c1257 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -18,8 +18,8 @@ package com.android.systemui.theme;
import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.Flags.themeOverlayControllerWakefulnessDeprecation;
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_HOME;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_LOCK;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_PRESET;
@@ -364,15 +364,23 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- boolean newWorkProfile = Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction());
- boolean isManagedProfile = mUserManager.isManagedProfile(
- intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
- if (newWorkProfile) {
- if (!mDeviceProvisionedController.isCurrentUserSetup() && isManagedProfile) {
+ boolean newProfile = Intent.ACTION_PROFILE_ADDED.equals(intent.getAction());
+ if (newProfile) {
+ UserHandle newUserHandle = intent.getParcelableExtra(Intent.EXTRA_USER,
+ android.os.UserHandle.class);
+ boolean isManagedProfile =
+ mUserManager.isManagedProfile(newUserHandle.getIdentifier());
+ if (!mDeviceProvisionedController.isUserSetup(newUserHandle.getIdentifier())
+ && isManagedProfile) {
Log.i(TAG, "User setup not finished when " + intent.getAction()
+ " was received. Deferring... Managed profile? " + isManagedProfile);
return;
}
+ if (android.os.Flags.allowPrivateProfile() && isPrivateProfile(newUserHandle)) {
+ mDeferredThemeEvaluation = true;
+ Log.i(TAG, "Deferring theme for private profile till user setup is complete");
+ return;
+ }
if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
reevaluateSystemTheme(true /* forceReload */);
} else if (Intent.ACTION_WALLPAPER_CHANGED.equals(intent.getAction())) {
@@ -432,7 +440,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
public void start() {
if (DEBUG) Log.d(TAG, "Start");
final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+ filter.addAction(Intent.ACTION_PROFILE_ADDED);
filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mMainExecutor,
UserHandle.ALL);
@@ -608,6 +616,15 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
return new FabricatedOverlay.Builder("com.android.systemui", name, "android").build();
}
+ @VisibleForTesting
+ protected boolean isPrivateProfile(UserHandle userHandle) {
+ Context usercontext = mContext.createContextAsUser(userHandle,0);
+ if (usercontext.getSystemService(UserManager.class).isPrivateProfile()) {
+ return true;
+ }
+ return false;
+ }
+
private void createOverlays(int color) {
boolean nightMode = isNightMode();
mColorScheme = new ColorScheme(color, nightMode, mThemeStyle);
@@ -784,7 +801,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
Set<UserHandle> managedProfiles = new HashSet<>();
for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) {
- if (userInfo.isManagedProfile()) {
+ if (userInfo.isProfile()) {
managedProfiles.add(userInfo.getUserHandle());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
index 3ed05aac3e10..0fb4b43865aa 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
@@ -2,9 +2,8 @@ package com.android.systemui.user.domain.interactor
import android.annotation.UserIdInt
import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.Flags.refactorGetCurrentUser
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER
import com.android.systemui.user.data.repository.UserRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -12,12 +11,7 @@ import kotlinx.coroutines.flow.map
/** Encapsulates business logic to interact the selected user */
@SysUISingleton
-class SelectedUserInteractor
-@Inject
-constructor(
- private val repository: UserRepository,
- private val flags: FeatureFlagsClassic,
-) {
+class SelectedUserInteractor @Inject constructor(private val repository: UserRepository) {
/** Flow providing the ID of the currently selected user. */
val selectedUser = repository.selectedUserInfo.map { it.id }.distinctUntilChanged()
@@ -34,7 +28,7 @@ constructor(
@UserIdInt
@JvmOverloads
fun getSelectedUserId(bypassFlag: Boolean = false): Int {
- return if (bypassFlag || flags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ return if (bypassFlag || refactorGetCurrentUser()) {
repository.getSelectedUserInfo().id
} else {
KeyguardUpdateMonitor.getCurrentUser()
diff --git a/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt b/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
index 5b0943a77979..a89fdda01537 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
@@ -60,6 +60,12 @@ fun IndentingPrintWriter.withIncreasedIndent(runnable: Runnable) {
fun IndentingPrintWriter.println(label: String, value: Any?) =
append(label).append('=').println(value)
+/** Print a section with a header using the given name and an indented body */
+inline fun IndentingPrintWriter.printSection(sectionName: String, block: () -> Unit) {
+ append(sectionName).println(":")
+ withIncreasedIndent(block)
+}
+
@JvmOverloads
inline fun <T> IndentingPrintWriter.printCollection(
label: String,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index ea20d29556dc..91219f02818c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -47,12 +47,14 @@ import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorI
import com.android.systemui.biometrics.domain.interactor.FakeCredentialInteractor
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.events.ANIMATING_OUT
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -101,6 +103,12 @@ open class AuthContainerViewTest : SysuiTestCase() {
lateinit var interactionJankMonitor: InteractionJankMonitor
@Mock
lateinit var vibrator: VibratorHelper
+ @Mock
+ lateinit var udfpsUtils: UdfpsUtils
+ @Mock
+ lateinit var authController: AuthController
+ @Mock
+ lateinit var selectedUserInteractor: SelectedUserInteractor
private val testScope = TestScope(StandardTestDispatcher())
private val fakeExecutor = FakeExecutor(FakeSystemClock())
@@ -123,6 +131,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
private lateinit var displayRepository: FakeDisplayRepository
private lateinit var displayStateInteractor: DisplayStateInteractor
+ private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor)
@@ -140,6 +149,12 @@ open class AuthContainerViewTest : SysuiTestCase() {
displayStateRepository,
displayRepository,
)
+ udfpsOverlayInteractor =
+ UdfpsOverlayInteractor(
+ authController,
+ selectedUserInteractor,
+ testScope.backgroundScope,
+ )
}
@After
@@ -532,6 +547,8 @@ open class AuthContainerViewTest : SysuiTestCase() {
displayStateInteractor,
promptSelectorInteractor,
context,
+ udfpsOverlayInteractor,
+ udfpsUtils
),
{ credentialViewModel },
Handler(TestableLooper.get(this).looper),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 8e54eb7334dd..4c510ee0b8a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -27,6 +27,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.logging.KeyguardLogger
+import com.android.systemui.Flags.FLAG_LIGHT_REVEAL_MIGRATION
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FeatureFlags
@@ -40,6 +41,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.leak.RotationUtils
import com.android.systemui.util.mockito.any
+import javax.inject.Provider
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -51,14 +53,14 @@ import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.eq
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import javax.inject.Provider
+
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -246,6 +248,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
@Test
@RunWithLooper(setAsMainLooper = true)
fun testAnimatorRunWhenWakeAndUnlock_fingerprint() {
+ mSetFlagsRule.disableFlags(FLAG_LIGHT_REVEAL_MIGRATION)
val fpsLocation = Point(5, 5)
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
@@ -266,6 +269,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
@Test
@RunWithLooper(setAsMainLooper = true)
fun testAnimatorRunWhenWakeAndUnlock_faceUdfpsFingerDown() {
+ mSetFlagsRule.disableFlags(FLAG_LIGHT_REVEAL_MIGRATION)
val faceLocation = Point(5, 5)
`when`(authController.faceSensorLocation).thenReturn(faceLocation)
controller.onViewAttached()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt
new file mode 100644
index 000000000000..27d93eb31922
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt
@@ -0,0 +1,176 @@
+/*
+ * 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.biometrics.data.repository
+
+import android.hardware.biometrics.AuthenticationStateListener
+import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import android.platform.test.annotations.RequiresFlagsEnabled
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+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.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@RequiresFlagsEnabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class BiometricStatusRepositoryTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Mock private lateinit var biometricManager: BiometricManager
+
+ private lateinit var underTest: BiometricStatusRepository
+
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ @Before
+ fun setUp() {
+ underTest = BiometricStatusRepositoryImpl(testScope.backgroundScope, biometricManager)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenBiometricPromptAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_BP)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.BiometricPromptAuthentication)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenDeviceEntryAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_KEYGUARD)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.DeviceEntryAuthentication)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenOtherAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_OTHER)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.OtherAuthentication)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenSettingsAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_SETTINGS)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER))
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenEnrollmentAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_ENROLL_FIND_SENSOR)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_FIND_SENSOR
+ )
+ )
+
+ listener.onAuthenticationStarted(REASON_ENROLL_ENROLLING)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
+ )
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenAuthenticationStopped() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ listener.onAuthenticationStarted(REASON_AUTH_BP)
+ listener.onAuthenticationStopped()
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+}
+
+private fun BiometricManager.captureListener() =
+ withArgCaptor<AuthenticationStateListener> {
+ verify(this@captureListener).registerAuthenticationStateListener(capture())
+ }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt
new file mode 100644
index 000000000000..6978923879b4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt
@@ -0,0 +1,173 @@
+/*
+ * 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.biometrics.domain.interactor
+
+import android.app.ActivityManager
+import android.app.ActivityTaskManager
+import android.content.ComponentName
+import android.platform.test.annotations.RequiresFlagsEnabled
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@RequiresFlagsEnabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class BiometricStatusInteractorImplTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Mock private lateinit var activityTaskManager: ActivityTaskManager
+
+ private lateinit var biometricStatusRepository: FakeBiometricStatusRepository
+ private lateinit var underTest: BiometricStatusInteractorImpl
+
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ @Before
+ fun setup() {
+ biometricStatusRepository = FakeBiometricStatusRepository()
+ underTest = BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
+ }
+
+ @Test
+ fun updatesSfpsAuthenticationReason_whenBiometricPromptAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ assertThat(sfpsAuthenticationReason)
+ .isEqualTo(AuthenticationReason.BiometricPromptAuthentication)
+ }
+
+ @Test
+ fun doesNotUpdateSfpsAuthenticationReason_whenDeviceEntryAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.DeviceEntryAuthentication
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+
+ @Test
+ fun updatesSfpsAuthenticationReason_whenOtherAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.OtherAuthentication
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.OtherAuthentication)
+ }
+
+ @Test
+ fun doesNotUpdateSfpsAuthenticationReason_whenOtherSettingsAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ `when`(activityTaskManager.getTasks(Mockito.anyInt()))
+ .thenReturn(listOf(fpSettingsTask()))
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER)
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+
+ @Test
+ fun updatesSfpsAuthenticationReason_whenEnrollmentAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_FIND_SENSOR)
+ )
+ assertThat(sfpsAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_FIND_SENSOR
+ )
+ )
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
+ )
+ assertThat(sfpsAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
+ )
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenAuthenticationStopped() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+}
+
+private fun fpSettingsTask() = settingsTask(".biometrics.fingerprint.FingerprintSettings")
+
+private fun settingsTask(cls: String) =
+ ActivityManager.RunningTaskInfo().apply {
+ topActivity = ComponentName.createRelative("com.android.settings", cls)
+ }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
index 22e3e7fedda0..74c43131b955 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics.shared.model
+import android.hardware.fingerprint.FingerprintSensorProperties
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.faceSensorPropertiesInternal
@@ -35,6 +36,46 @@ class BiometricModalitiesTest : SysuiTestCase() {
}
@Test
+ fun hasUdfps() {
+ with(
+ BiometricModalities(
+ fingerprintProperties = fingerprintSensorPropertiesInternal(
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
+ ).first(),
+ )
+ ) {
+ assertThat(isEmpty).isFalse()
+ assertThat(hasUdfps).isTrue()
+ assertThat(hasSfps).isFalse()
+ assertThat(hasFace).isFalse()
+ assertThat(hasFaceOnly).isFalse()
+ assertThat(hasFingerprint).isTrue()
+ assertThat(hasFingerprintOnly).isTrue()
+ assertThat(hasFaceAndFingerprint).isFalse()
+ }
+ }
+
+ @Test
+ fun hasSfps() {
+ with(
+ BiometricModalities(
+ fingerprintProperties = fingerprintSensorPropertiesInternal(
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ ).first(),
+ )
+ ) {
+ assertThat(isEmpty).isFalse()
+ assertThat(hasUdfps).isFalse()
+ assertThat(hasSfps).isTrue()
+ assertThat(hasFace).isFalse()
+ assertThat(hasFaceOnly).isFalse()
+ assertThat(hasFingerprint).isTrue()
+ assertThat(hasFingerprintOnly).isTrue()
+ assertThat(hasFaceAndFingerprint).isFalse()
+ }
+ }
+
+ @Test
fun fingerprintOnly() {
with(
BiometricModalities(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
new file mode 100644
index 000000000000..b4ae00ddd608
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
@@ -0,0 +1,484 @@
+/*
+ * 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.biometrics.ui.binder
+
+import android.animation.Animator
+import android.app.ActivityTaskManager
+import android.graphics.Rect
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.display.DisplayManager
+import android.hardware.display.DisplayManagerGlobal
+import android.os.Handler
+import android.testing.TestableLooper
+import android.view.Display
+import android.view.DisplayInfo
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewPropertyAnimator
+import android.view.WindowInsets
+import android.view.WindowManager
+import android.view.WindowMetrics
+import androidx.test.filters.SmallTest
+import com.airbnb.lottie.LottieAnimationView
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider
+import com.android.systemui.biometrics.FpsUnlockTracker
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
+import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.dump.logcatLogBuffer
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.log.SideFpsLogger
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import java.util.Optional
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.any
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class SideFpsOverlayViewBinderTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Mock private lateinit var activityTaskManager: ActivityTaskManager
+ @Mock private lateinit var displayManager: DisplayManager
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
+ @Mock
+ private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider
+ @Mock private lateinit var fpsUnlockTracker: FpsUnlockTracker
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var layoutInflater: LayoutInflater
+ @Mock private lateinit var screenSizeFoldProvider: ScreenSizeFoldProvider
+ @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var sideFpsView: View
+ @Mock private lateinit var windowManager: WindowManager
+
+ private val contextDisplayInfo = DisplayInfo()
+
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val biometricSettingsRepository = FakeBiometricSettingsRepository()
+ private val biometricStatusRepository = FakeBiometricStatusRepository()
+ private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
+ private val displayRepository = FakeDisplayRepository()
+ private val displayStateRepository = FakeDisplayStateRepository()
+ private val fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+
+ private lateinit var underTest: SideFpsOverlayViewBinder
+
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ private lateinit var biometricStatusInteractor: BiometricStatusInteractor
+ private lateinit var deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor
+ private lateinit var displayStateInteractor: DisplayStateInteractorImpl
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ private lateinit var sfpsSensorInteractor: SideFpsSensorInteractor
+
+ private lateinit var sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
+
+ private lateinit var viewModel: SideFpsOverlayViewModel
+
+ private var displayWidth: Int = 0
+ private var displayHeight: Int = 0
+ private var boundsWidth: Int = 0
+ private var boundsHeight: Int = 0
+
+ private lateinit var deviceConfig: DeviceConfig
+ private lateinit var sensorLocation: SensorLocationInternal
+
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
+
+ enum class DeviceConfig {
+ X_ALIGNED,
+ Y_ALIGNED,
+ }
+
+ @Before
+ fun setup() {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+
+ allowTestableLooperAsMainThread() // repeatWhenAttached requires the main thread
+
+ mContext = spy(mContext)
+
+ val resources = mContext.resources
+ whenever(mContext.display)
+ .thenReturn(
+ Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources)
+ )
+
+ alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ mock(StatusBarStateController::class.java),
+ mock(KeyguardStateController::class.java),
+ bouncerRepository,
+ fingerprintPropertyRepository,
+ biometricSettingsRepository,
+ FakeSystemClock(),
+ keyguardUpdateMonitor,
+ testScope.backgroundScope,
+ )
+
+ biometricStatusInteractor =
+ BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
+
+ displayStateInteractor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ displayStateRepository,
+ displayRepository,
+ )
+ displayStateInteractor.setScreenSizeFoldProvider(screenSizeFoldProvider)
+
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ mContext,
+ keyguardUpdateMonitor,
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ selectedUserInteractor,
+ faceAuthInteractor
+ )
+
+ deviceEntrySideFpsOverlayInteractor =
+ DeviceEntrySideFpsOverlayInteractor(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+
+ whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser)
+ .thenReturn(MutableStateFlow(false))
+
+ sfpsSensorInteractor =
+ SideFpsSensorInteractor(
+ mContext,
+ fingerprintPropertyRepository,
+ windowManager,
+ displayStateInteractor,
+ Optional.of(fingerprintInteractiveToAuthProvider),
+ SideFpsLogger(logcatLogBuffer("SfpsLogger"))
+ )
+
+ sideFpsProgressBarViewModel =
+ SideFpsProgressBarViewModel(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ sfpsSensorInteractor,
+ displayStateInteractor,
+ testScope.backgroundScope,
+ )
+
+ viewModel =
+ SideFpsOverlayViewModel(
+ mContext,
+ biometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor,
+ sfpsSensorInteractor,
+ sideFpsProgressBarViewModel
+ )
+
+ underTest =
+ SideFpsOverlayViewBinder(
+ testScope.backgroundScope,
+ mContext,
+ biometricStatusInteractor,
+ displayStateInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ fpsUnlockTracker,
+ layoutInflater,
+ sideFpsProgressBarViewModel,
+ sfpsSensorInteractor,
+ windowManager
+ )
+
+ context.addMockSystemService(DisplayManager::class.java, displayManager)
+ context.addMockSystemService(WindowManager::class.java, windowManager)
+
+ `when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sideFpsView)
+ `when`(sideFpsView.requireViewById<LottieAnimationView>(eq(R.id.sidefps_animation)))
+ .thenReturn(mock(LottieAnimationView::class.java))
+ with(mock(ViewPropertyAnimator::class.java)) {
+ `when`(sideFpsView.animate()).thenReturn(this)
+ `when`(alpha(Mockito.anyFloat())).thenReturn(this)
+ `when`(setStartDelay(Mockito.anyLong())).thenReturn(this)
+ `when`(setDuration(Mockito.anyLong())).thenReturn(this)
+ `when`(setListener(any())).thenAnswer {
+ (it.arguments[0] as Animator.AnimatorListener).onAnimationEnd(
+ mock(Animator::class.java)
+ )
+ this
+ }
+ }
+ }
+
+ @Test
+ fun verifyIndicatorNotAdded_whenInRearDisplayMode() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = true
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ verify(windowManager, never()).addView(any(), any())
+ }
+ }
+
+ @Test
+ fun verifyIndicatorShowAndHide_onPrimaryBouncerShowAndHide() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ // Show primary bouncer
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ verify(windowManager).addView(any(), any())
+
+ // Hide primary bouncer
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ verify(windowManager).removeView(any())
+ }
+ }
+
+ @Test
+ fun verifyIndicatorShowAndHide_onAlternateBouncerShowAndHide() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ // Show alternate bouncer
+ bouncerRepository.setAlternateVisible(true)
+ runCurrent()
+
+ verify(windowManager).addView(any(), any())
+
+ // Hide alternate bouncer
+ bouncerRepository.setAlternateVisible(false)
+ runCurrent()
+
+ verify(windowManager).removeView(any())
+ }
+ }
+
+ @Test
+ fun verifyIndicatorShownAndHidden_onSystemServerAuthenticationStartedAndStopped() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ // System server authentication started
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ runCurrent()
+
+ verify(windowManager).addView(any(), any())
+
+ // System server authentication stopped
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ runCurrent()
+
+ verify(windowManager).removeView(any())
+ }
+ }
+
+ private fun updatePrimaryBouncer(
+ isShowing: Boolean,
+ isAnimatingAway: Boolean,
+ fpsDetectionRunning: Boolean,
+ isUnlockingWithFpAllowed: Boolean,
+ ) {
+ bouncerRepository.setPrimaryShow(isShowing)
+ bouncerRepository.setPrimaryStartingToHide(false)
+ val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
+ bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+
+ whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ .thenReturn(fpsDetectionRunning)
+ whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ .thenReturn(isUnlockingWithFpAllowed)
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_show_sidefps_hint_on_bouncer,
+ true
+ )
+ }
+
+ private suspend fun TestScope.setupTestConfiguration(
+ deviceConfig: DeviceConfig,
+ rotation: DisplayRotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode: Boolean,
+ ) {
+ this@SideFpsOverlayViewBinderTest.deviceConfig = deviceConfig
+
+ when (deviceConfig) {
+ DeviceConfig.X_ALIGNED -> {
+ displayWidth = 3000
+ displayHeight = 1500
+ boundsWidth = 200
+ boundsHeight = 100
+ sensorLocation = SensorLocationInternal("", 2500, 0, boundsWidth / 2)
+ }
+ DeviceConfig.Y_ALIGNED -> {
+ displayWidth = 2500
+ displayHeight = 2000
+ boundsWidth = 100
+ boundsHeight = 200
+ sensorLocation = SensorLocationInternal("", displayWidth, 300, boundsHeight / 2)
+ }
+ }
+
+ whenever(windowManager.maximumWindowMetrics)
+ .thenReturn(
+ WindowMetrics(
+ Rect(0, 0, displayWidth, displayHeight),
+ mock(WindowInsets::class.java),
+ )
+ )
+
+ contextDisplayInfo.uniqueId = DISPLAY_ID
+
+ fingerprintPropertyRepository.setProperties(
+ sensorId = 1,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.POWER_BUTTON,
+ sensorLocations = mapOf(DISPLAY_ID to sensorLocation)
+ )
+
+ displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode)
+ displayStateRepository.setCurrentRotation(rotation)
+ displayRepository.emitDisplayChangeEvent(0)
+ underTest.start()
+ runCurrent()
+ }
+
+ companion object {
+ private const val DISPLAY_ID = "displayId"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index d06cbbb5e433..7475235cfeae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.ui.viewmodel
import android.content.res.Configuration
+import android.graphics.Point
import android.hardware.biometrics.PromptInfo
import android.hardware.face.FaceSensorPropertiesInternal
import android.hardware.fingerprint.FingerprintSensorProperties
@@ -25,7 +26,10 @@ import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.Flags.FLAG_BP_TALKBACK
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.UdfpsUtils
import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
@@ -33,6 +37,7 @@ import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.biometrics.extractAuthenticatorTypes
import com.android.systemui.biometrics.faceSensorPropertiesInternal
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
@@ -45,8 +50,10 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.res.R
-import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -77,7 +84,9 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
@Mock private lateinit var lockPatternUtils: LockPatternUtils
- @Mock private lateinit var vibrator: VibratorHelper
+ @Mock private lateinit var authController: AuthController
+ @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var udfpsUtils: UdfpsUtils
private val fakeExecutor = FakeExecutor(FakeSystemClock())
private val testScope = TestScope()
@@ -87,6 +96,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
private lateinit var displayStateRepository: FakeDisplayStateRepository
private lateinit var displayRepository: FakeDisplayRepository
private lateinit var displayStateInteractor: DisplayStateInteractor
+ private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
private lateinit var selector: PromptSelectorInteractor
private lateinit var viewModel: PromptViewModel
@@ -116,11 +126,24 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
displayStateRepository,
displayRepository,
)
+ udfpsOverlayInteractor =
+ UdfpsOverlayInteractor(
+ authController,
+ selectedUserInteractor,
+ testScope.backgroundScope
+ )
selector =
PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
selector.resetPrompt()
- viewModel = PromptViewModel(displayStateInteractor, selector, mContext)
+ viewModel =
+ PromptViewModel(
+ displayStateInteractor,
+ selector,
+ mContext,
+ udfpsOverlayInteractor,
+ udfpsUtils
+ )
iconViewModel = viewModel.iconViewModel
}
@@ -1153,6 +1176,29 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(size).isEqualTo(PromptSize.LARGE)
}
+ @Test
+ fun hint_for_talkback_guidance() = runGenericTest {
+ mSetFlagsRule.enableFlags(FLAG_BP_TALKBACK)
+ val hint by collectLastValue(viewModel.accessibilityHint)
+
+ // Touches should fall outside of sensor area
+ whenever(udfpsUtils.getTouchInNativeCoordinates(any(), any(), any()))
+ .thenReturn(Point(0, 0))
+ whenever(udfpsUtils.onTouchOutsideOfSensorArea(any(), any(), any(), any(), any()))
+ .thenReturn("Direction")
+
+ viewModel.onAnnounceAccessibilityHint(
+ obtainMotionEvent(MotionEvent.ACTION_HOVER_ENTER),
+ true
+ )
+
+ if (testCase.modalities.hasUdfps) {
+ assertThat(hint?.isNotBlank()).isTrue()
+ } else {
+ assertThat(hint.isNullOrBlank()).isTrue()
+ }
+ }
+
/** Asserts that the selected buttons are visible now. */
private suspend fun TestScope.assertButtonsVisible(
tryAgain: Boolean = false,
@@ -1220,14 +1266,19 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
authenticatedModality = BiometricModality.Face,
),
TestCase(
- fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
+ fingerprint =
+ fingerprintSensorPropertiesInternal(
+ strong = true,
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ )
+ .first(),
authenticatedModality = BiometricModality.Fingerprint,
),
TestCase(
fingerprint =
fingerprintSensorPropertiesInternal(
strong = true,
- sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
)
.first(),
authenticatedModality = BiometricModality.Fingerprint,
@@ -1264,19 +1315,29 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
TestCase(
face = faceSensorPropertiesInternal(strong = true).first(),
fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
- authenticatedModality = BiometricModality.Fingerprint,
+ authenticatedModality = BiometricModality.Face,
+ confirmationRequested = true,
),
TestCase(
face = faceSensorPropertiesInternal(strong = true).first(),
- fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
- authenticatedModality = BiometricModality.Face,
+ fingerprint =
+ fingerprintSensorPropertiesInternal(
+ strong = true,
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ )
+ .first(),
+ authenticatedModality = BiometricModality.Fingerprint,
confirmationRequested = true,
),
TestCase(
face = faceSensorPropertiesInternal(strong = true).first(),
- fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
+ fingerprint =
+ fingerprintSensorPropertiesInternal(
+ strong = true,
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
+ )
+ .first(),
authenticatedModality = BiometricModality.Fingerprint,
- confirmationRequested = true,
),
)
}
@@ -1309,6 +1370,9 @@ internal data class TestCase(
else -> false
}
+ val modalities: BiometricModalities
+ get() = BiometricModalities(fingerprint, face)
+
val authenticatedByFingerprint: Boolean
get() = authenticatedModality == BiometricModality.Fingerprint
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
new file mode 100644
index 000000000000..2267bdcafad8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
@@ -0,0 +1,576 @@
+/*
+ * 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.biometrics.ui.viewmodel
+
+import android.app.ActivityTaskManager
+import android.content.res.Configuration.UI_MODE_NIGHT_NO
+import android.content.res.Configuration.UI_MODE_NIGHT_YES
+import android.graphics.Color
+import android.graphics.Rect
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.display.DisplayManagerGlobal
+import android.os.Handler
+import android.view.Display
+import android.view.DisplayInfo
+import android.view.WindowInsets
+import android.view.WindowManager
+import android.view.WindowMetrics
+import androidx.test.filters.SmallTest
+import com.airbnb.lottie.model.KeyPath
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.settingslib.Utils
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
+import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.LottieCallback
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.dump.logcatLogBuffer
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.log.SideFpsLogger
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class SideFpsOverlayViewModelTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var activityTaskManager: ActivityTaskManager
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
+ @Mock
+ private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var screenSizeFoldProvider: ScreenSizeFoldProvider
+ @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var windowManager: WindowManager
+
+ private val contextDisplayInfo = DisplayInfo()
+
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val biometricSettingsRepository = FakeBiometricSettingsRepository()
+ private val biometricStatusRepository = FakeBiometricStatusRepository()
+ private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
+ private val displayRepository = FakeDisplayRepository()
+ private val displayStateRepository = FakeDisplayStateRepository()
+ private val fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+
+ private val indicatorColor =
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.materialColorPrimaryFixed
+ )
+ private val outerRimColor =
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.materialColorPrimaryFixedDim
+ )
+ private val chevronFill =
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.materialColorOnPrimaryFixed
+ )
+ private val color_blue400 =
+ context.getColor(com.android.settingslib.color.R.color.settingslib_color_blue400)
+
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ private lateinit var biometricStatusInteractor: BiometricStatusInteractor
+ private lateinit var deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor
+ private lateinit var displayStateInteractor: DisplayStateInteractorImpl
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ private lateinit var sfpsSensorInteractor: SideFpsSensorInteractor
+
+ private lateinit var sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
+
+ private lateinit var underTest: SideFpsOverlayViewModel
+
+ private var displayWidth: Int = 0
+ private var displayHeight: Int = 0
+ private var boundsWidth: Int = 0
+ private var boundsHeight: Int = 0
+
+ private lateinit var deviceConfig: DeviceConfig
+ private lateinit var sensorLocation: SensorLocationInternal
+
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
+
+ enum class DeviceConfig {
+ X_ALIGNED,
+ Y_ALIGNED,
+ }
+
+ @Before
+ fun setup() {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+
+ mContext = spy(mContext)
+
+ val resources = mContext.resources
+ whenever(mContext.display)
+ .thenReturn(
+ Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources)
+ )
+
+ alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ mock(StatusBarStateController::class.java),
+ mock(KeyguardStateController::class.java),
+ bouncerRepository,
+ fingerprintPropertyRepository,
+ biometricSettingsRepository,
+ FakeSystemClock(),
+ keyguardUpdateMonitor,
+ testScope.backgroundScope,
+ )
+
+ biometricStatusInteractor =
+ BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
+
+ displayStateInteractor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ displayStateRepository,
+ displayRepository,
+ )
+ displayStateInteractor.setScreenSizeFoldProvider(screenSizeFoldProvider)
+
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ mContext,
+ keyguardUpdateMonitor,
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ selectedUserInteractor,
+ faceAuthInteractor
+ )
+
+ deviceEntrySideFpsOverlayInteractor =
+ DeviceEntrySideFpsOverlayInteractor(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+
+ whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser)
+ .thenReturn(MutableStateFlow(false))
+
+ sfpsSensorInteractor =
+ SideFpsSensorInteractor(
+ mContext,
+ fingerprintPropertyRepository,
+ windowManager,
+ displayStateInteractor,
+ Optional.of(fingerprintInteractiveToAuthProvider),
+ SideFpsLogger(logcatLogBuffer("SfpsLogger"))
+ )
+
+ sideFpsProgressBarViewModel =
+ SideFpsProgressBarViewModel(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ sfpsSensorInteractor,
+ displayStateInteractor,
+ testScope.backgroundScope,
+ )
+
+ underTest =
+ SideFpsOverlayViewModel(
+ mContext,
+ biometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor,
+ sfpsSensorInteractor,
+ sideFpsProgressBarViewModel,
+ )
+ }
+
+ @Test
+ fun updatesOverlayViewProperties_onDisplayRotationChange_xAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewProperties by collectLastValue(underTest.overlayViewProperties)
+
+ runCurrent()
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+ }
+ }
+
+ @Test
+ fun updatesOverlayViewProperties_onDisplayRotationChange_yAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.Y_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewProperties by collectLastValue(underTest.overlayViewProperties)
+
+ runCurrent()
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_0)
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+ }
+ }
+
+ @Test
+ fun updatesOverlayViewParams_onDisplayRotationChange_xAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewParams by collectLastValue(underTest.overlayViewParams)
+
+ underTest.setLottieBounds(Rect(0, 0, boundsWidth, boundsHeight))
+ runCurrent()
+
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(sensorLocation.sensorLocationX)
+ assertThat(overlayViewParams!!.y).isEqualTo(0)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(0)
+ assertThat(overlayViewParams!!.y)
+ .isEqualTo(
+ displayHeight - sensorLocation.sensorLocationX - sensorLocation.sensorRadius * 2
+ )
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x)
+ .isEqualTo(
+ displayWidth - sensorLocation.sensorLocationX - sensorLocation.sensorRadius * 2
+ )
+ assertThat(overlayViewParams!!.y).isEqualTo(displayHeight - boundsHeight)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(displayWidth - boundsWidth)
+ assertThat(overlayViewParams!!.y).isEqualTo(sensorLocation.sensorLocationX)
+ }
+ }
+
+ @Test
+ fun updatesOverlayViewParams_onDisplayRotationChange_yAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.Y_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewParams by collectLastValue(underTest.overlayViewParams)
+
+ underTest.setLottieBounds(Rect(0, 0, boundsWidth, boundsHeight))
+ runCurrent()
+
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(displayWidth - boundsWidth)
+ assertThat(overlayViewParams!!.y).isEqualTo(sensorLocation.sensorLocationY)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(sensorLocation.sensorLocationY)
+ assertThat(overlayViewParams!!.y).isEqualTo(0)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(0)
+ assertThat(overlayViewParams!!.y)
+ .isEqualTo(
+ displayHeight - sensorLocation.sensorLocationY - sensorLocation.sensorRadius * 2
+ )
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x)
+ .isEqualTo(
+ displayWidth - sensorLocation.sensorLocationY - sensorLocation.sensorRadius * 2
+ )
+ assertThat(overlayViewParams!!.y).isEqualTo(displayHeight - boundsHeight)
+ }
+ }
+
+ @Test
+ fun updatesLottieCallbacks_onShowIndicatorForDeviceEntry() {
+ testScope.runTest {
+ val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue600", "**"), indicatorColor))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue400", "**"), outerRimColor))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".black", "**"), chevronFill))
+ }
+ }
+
+ @Test
+ fun updatesLottieCallbacks_onShowIndicatorForSystemServer_inDarkMode() {
+ testScope.runTest {
+ val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+ setDarkMode(true)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue600", "**"), color_blue400))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue400", "**"), color_blue400))
+ }
+ }
+
+ @Test
+ fun updatesLottieCallbacks_onShowIndicatorForSystemServer_inLightMode() {
+ testScope.runTest {
+ val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+ setDarkMode(false)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".black", "**"), Color.WHITE))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue600", "**"), color_blue400))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue400", "**"), color_blue400))
+ }
+ }
+
+ private fun setDarkMode(inDarkMode: Boolean) {
+ val uiMode =
+ if (inDarkMode) {
+ UI_MODE_NIGHT_YES
+ } else {
+ UI_MODE_NIGHT_NO
+ }
+
+ mContext.resources.configuration.uiMode = uiMode
+ }
+
+ private fun updatePrimaryBouncer(
+ isShowing: Boolean,
+ isAnimatingAway: Boolean,
+ fpsDetectionRunning: Boolean,
+ isUnlockingWithFpAllowed: Boolean,
+ ) {
+ bouncerRepository.setPrimaryShow(isShowing)
+ bouncerRepository.setPrimaryStartingToHide(false)
+ val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
+ bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+
+ whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ .thenReturn(fpsDetectionRunning)
+ whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ .thenReturn(isUnlockingWithFpAllowed)
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_show_sidefps_hint_on_bouncer,
+ true
+ )
+ }
+
+ private suspend fun TestScope.setupTestConfiguration(
+ deviceConfig: DeviceConfig,
+ rotation: DisplayRotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode: Boolean,
+ ) {
+ this@SideFpsOverlayViewModelTest.deviceConfig = deviceConfig
+
+ when (deviceConfig) {
+ DeviceConfig.X_ALIGNED -> {
+ displayWidth = 3000
+ displayHeight = 1500
+ boundsWidth = 200
+ boundsHeight = 100
+ sensorLocation = SensorLocationInternal("", 2500, 0, boundsWidth / 2)
+ }
+ DeviceConfig.Y_ALIGNED -> {
+ displayWidth = 2500
+ displayHeight = 2000
+ boundsWidth = 100
+ boundsHeight = 200
+ sensorLocation = SensorLocationInternal("", displayWidth, 300, boundsHeight / 2)
+ }
+ }
+
+ whenever(windowManager.maximumWindowMetrics)
+ .thenReturn(
+ WindowMetrics(
+ Rect(0, 0, displayWidth, displayHeight),
+ mock(WindowInsets::class.java),
+ )
+ )
+
+ contextDisplayInfo.uniqueId = DISPLAY_ID
+
+ fingerprintPropertyRepository.setProperties(
+ sensorId = 1,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.POWER_BUTTON,
+ sensorLocations = mapOf(DISPLAY_ID to sensorLocation)
+ )
+
+ displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode)
+
+ displayStateRepository.setCurrentRotation(rotation)
+
+ displayRepository.emitDisplayChangeEvent(0)
+ runCurrent()
+ }
+
+ companion object {
+ private const val DISPLAY_ID = "displayId"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
index 37a093e4c23f..dacf23a5a567 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -37,6 +37,7 @@ import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.any
@@ -342,6 +343,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
assertThat(underTest.willDismissWithAction()).isFalse()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility() {
updateSideFpsVisibilityParameters(
@@ -355,6 +357,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
verify(repository).setSideFpsShowing(true)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_notVisible() {
updateSideFpsVisibilityParameters(
@@ -368,6 +371,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_sfpsNotEnabled() {
updateSideFpsVisibilityParameters(
@@ -381,6 +385,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_fpsDetectionNotRunning() {
updateSideFpsVisibilityParameters(
@@ -394,6 +399,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_UnlockingWithFpNotAllowed() {
updateSideFpsVisibilityParameters(
@@ -407,6 +413,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_AnimatingAway() {
updateSideFpsVisibilityParameters(
@@ -492,6 +499,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
isUnlockingWithFpAllowed: Boolean,
isAnimatingAway: Boolean
) {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
whenever(repository.primaryBouncerShow.value).thenReturn(isVisible)
resources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer, sfpsEnabled)
whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
index 220718027eee..07c980bb6656 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
@@ -21,14 +21,13 @@ import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
-import android.content.Context;
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.view.View;
@@ -48,6 +47,7 @@ import com.android.systemui.controls.management.ControlsListingController;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
import org.junit.Test;
@@ -71,9 +71,6 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase {
private DreamOverlayStateController mDreamOverlayStateController;
@Mock
- private Context mContext;
-
- @Mock
private Resources mResources;
@Mock
@@ -100,6 +97,9 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase {
@Mock
private UiEventLogger mUiEventLogger;
+ @Mock
+ private ConfigurationController mConfigurationController;
+
@Captor
private ArgumentCaptor<DreamOverlayStateController.Callback> mStateCallbackCaptor;
@@ -109,7 +109,8 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
- when(mContext.getString(anyInt())).thenReturn("");
+ mContext.ensureTestableResources();
+
when(mControlsComponent.getControlsController()).thenReturn(
Optional.of(mControlsController));
when(mControlsComponent.getControlsListingController()).thenReturn(
@@ -225,6 +226,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase {
mHomeControlsView,
mActivityStarter,
mContext,
+ mConfigurationController,
mControlsComponent,
mUiEventLogger);
viewController.onViewAttached();
@@ -237,6 +239,24 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase {
verify(mUiEventLogger).log(DreamOverlayUiEvent.DREAM_HOME_CONTROLS_TAPPED);
}
+ @Test
+ public void testUnregistersConfigurationCallback() {
+ final DreamHomeControlsComplication.DreamHomeControlsChipViewController viewController =
+ new DreamHomeControlsComplication.DreamHomeControlsChipViewController(
+ mHomeControlsView,
+ mActivityStarter,
+ mContext,
+ mConfigurationController,
+ mControlsComponent,
+ mUiEventLogger);
+ viewController.onViewAttached();
+ verify(mConfigurationController).addCallback(any());
+ verify(mConfigurationController, never()).removeCallback(any());
+
+ viewController.onViewDetached();
+ verify(mConfigurationController).removeCallback(any());
+ }
+
private void setHaveFavorites(boolean value) {
final List<StructureInfo> favorites = mock(List.class);
when(favorites.isEmpty()).thenReturn(!value);
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 4ef18cf1a15f..b38c9ecb6287 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -24,6 +24,7 @@ import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.systemui.Flags.FLAG_REFACTOR_GET_CURRENT_USER;
import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
import static com.android.systemui.keyguard.KeyguardViewMediator.REBOOT_MAINLINE_UPDATE;
@@ -266,7 +267,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mSceneContainerFlags);
mFeatureFlags = new FakeFeatureFlags();
mFeatureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false);
- mFeatureFlags.set(Flags.REFACTOR_GETCURRENTUSER, true);
+ mSetFlagsRule.enableFlags(FLAG_REFACTOR_GET_CURRENT_USER);
DejankUtils.setImmediate(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
new file mode 100644
index 000000000000..70d3f81de35f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
@@ -0,0 +1,238 @@
+/*
+ * 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 android.os.Handler
+import android.platform.test.annotations.RequiresFlagsEnabled
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RequiresFlagsEnabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+@SmallTest
+@RunWith(JUnit4::class)
+class DeviceEntrySideFpsOverlayInteractorTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor
+
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val biometricSettingsRepository = FakeBiometricSettingsRepository()
+
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+
+ private lateinit var underTest: DeviceEntrySideFpsOverlayInteractor
+
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ @Before
+ fun setup() {
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ mContext,
+ keyguardUpdateMonitor,
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ mSelectedUserInteractor,
+ faceAuthInteractor
+ )
+ alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ mock(StatusBarStateController::class.java),
+ mock(KeyguardStateController::class.java),
+ bouncerRepository,
+ FakeFingerprintPropertyRepository(),
+ biometricSettingsRepository,
+ FakeSystemClock(),
+ keyguardUpdateMonitor,
+ testScope.backgroundScope,
+ )
+ underTest =
+ DeviceEntrySideFpsOverlayInteractor(
+ mContext,
+ FakeDeviceEntryFingerprintAuthRepository(),
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onPrimaryBouncerShowing() =
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(true)
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onPrimaryBouncerHidden() =
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_fromPrimaryBouncer_whenFpsDetectionNotRunning() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = false,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_fromPrimaryBouncer_onUnlockingWithFpDisallowed() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = false
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onPrimaryBouncerAnimatingAway() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = true,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onAlternateBouncerRequest() =
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ bouncerRepository.setAlternateVisible(true)
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(true)
+
+ bouncerRepository.setAlternateVisible(false)
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+
+ private fun updatePrimaryBouncer(
+ isShowing: Boolean,
+ isAnimatingAway: Boolean,
+ fpsDetectionRunning: Boolean,
+ isUnlockingWithFpAllowed: Boolean,
+ ) {
+ bouncerRepository.setPrimaryShow(isShowing)
+ bouncerRepository.setPrimaryStartingToHide(false)
+ val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
+ bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+
+ whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ .thenReturn(fpsDetectionRunning)
+ whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ .thenReturn(isUnlockingWithFpAllowed)
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_show_sidefps_hint_on_bouncer,
+ true
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
index 8dea57c2eb34..8e81185d6dcf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
@@ -20,8 +20,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -46,11 +44,7 @@ import org.junit.runner.RunWith
class FromPrimaryBouncerTransitionInteractorTest : KeyguardTransitionInteractorTestCase() {
private lateinit var underTest: FromPrimaryBouncerTransitionInteractor
- private val mSelectedUserInteractor =
- SelectedUserInteractor(
- FakeUserRepository(),
- FakeFeatureFlagsClassic().apply { set(Flags.REFACTOR_GETCURRENTUSER, true) }
- )
+ private val mSelectedUserInteractor = SelectedUserInteractor(FakeUserRepository())
// Override the fromPrimaryBouncerTransitionInteractor provider from the superclass so our
// underTest interactor is provided to any classes that need it.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index b7618d290f53..4d423242893a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -75,6 +75,7 @@ import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
@@ -462,6 +463,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
// region setNoteTaskShortcutEnabled
@Test
+ @Ignore("b/316332684")
fun setNoteTaskShortcutEnabled_setTrue() {
createNoteTaskController().setNoteTaskShortcutEnabled(value = true, userTracker.userHandle)
@@ -478,6 +480,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
}
@Test
+ @Ignore("b/316332684")
fun setNoteTaskShortcutEnabled_setFalse() {
createNoteTaskController().setNoteTaskShortcutEnabled(value = false, userTracker.userHandle)
@@ -494,6 +497,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
}
@Test
+ @Ignore("b/316332684")
fun setNoteTaskShortcutEnabled_workProfileUser_setTrue() {
whenever(context.createContextAsUser(eq(workUserInfo.userHandle), any()))
.thenReturn(workProfileContext)
@@ -515,6 +519,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
}
@Test
+ @Ignore("b/316332684")
fun setNoteTaskShortcutEnabled_workProfileUser_setFalse() {
whenever(context.createContextAsUser(eq(workUserInfo.userHandle), any()))
.thenReturn(workProfileContext)
@@ -733,6 +738,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
// region internalUpdateNoteTaskAsUser
@Test
+ @Ignore("b/316332684")
fun updateNoteTaskAsUserInternal_withNotesRole_withShortcuts_shouldUpdateShortcuts() {
createNoteTaskController(isEnabled = true)
.launchUpdateNoteTaskAsUser(userTracker.userHandle)
@@ -766,6 +772,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
}
@Test
+ @Ignore("b/316332684")
fun updateNoteTaskAsUserInternal_noNotesRole_shouldDisableShortcuts() {
whenever(roleManager.getRoleHoldersAsUser(ROLE_NOTES, userTracker.userHandle))
.thenReturn(emptyList())
@@ -789,6 +796,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
}
@Test
+ @Ignore("b/316332684")
fun updateNoteTaskAsUserInternal_flagDisabled_shouldDisableShortcuts() {
createNoteTaskController(isEnabled = false)
.launchUpdateNoteTaskAsUser(userTracker.userHandle)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
index 119ffd28bebe..ebd34de463f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
@@ -28,7 +28,6 @@ import android.os.UserManager
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import com.android.dx.mockito.inline.extended.ExtendedMockito
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -40,6 +39,7 @@ import com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity.C
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEntryPoint
import com.android.systemui.notetask.NoteTaskInfoResolver
+import com.android.systemui.res.R
import com.android.systemui.stylus.StylusManager
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -134,12 +134,9 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
// region lockScreenState
@Test
fun lockScreenState_stylusUsed_userUnlocked_isSelected_shouldEmitVisible() = runTest {
- TestConfig()
- .setStylusEverUsed(true)
- .setUserUnlocked(true)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
-
val underTest = createUnderTest()
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(underTest)
+
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(createLockScreenStateVisible())
@@ -148,10 +145,11 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
@Test
fun lockScreenState_stylusUsed_userUnlocked_isSelected_noDefaultNotesAppSet_shouldEmitHidden() =
runTest {
+ val underTest = createUnderTest()
TestConfig()
.setStylusEverUsed(true)
.setUserUnlocked(true)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
+ .setConfigSelections(underTest)
whenever(
roleManager.getRoleHoldersAsUser(
eq(RoleManager.ROLE_NOTES),
@@ -160,7 +158,6 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
)
.thenReturn(emptyList())
- val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
@@ -168,12 +165,9 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
@Test
fun lockScreenState_stylusUnused_userUnlocked_isSelected_shouldEmitHidden() = runTest {
- TestConfig()
- .setStylusEverUsed(false)
- .setUserUnlocked(true)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
-
val underTest = createUnderTest()
+ TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections(underTest)
+
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
@@ -181,25 +175,22 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
@Test
fun lockScreenState_stylusUsed_userLocked_isSelected_shouldEmitHidden() = runTest {
- TestConfig()
- .setStylusEverUsed(true)
- .setUserUnlocked(false)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
-
val underTest = createUnderTest()
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections(underTest)
+
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
@Test
- fun lockScreenState_stylusUsed_userUnlocked_noSelected_shouldEmitVisible() = runTest {
+ fun lockScreenState_stylusUsed_userUnlocked_noSelected_shouldEmitHidden() = runTest {
TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections()
val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(createLockScreenStateVisible())
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
@Test
@@ -223,13 +214,13 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
}
@Test
- fun lockScreenState_stylusUsed_userUnlocked_customSelections_shouldEmitVisible() = runTest {
+ fun lockScreenState_stylusUsed_userUnlocked_customSelections_shouldEmitHidden() = runTest {
TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(mock())
val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(createLockScreenStateVisible())
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index b825c0840e01..018fa9e2bc86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -391,7 +391,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
}
@Test
- public void setTiles_differentTiles_allTilesRemovedAndNewTilesAdded() {
+ public void setTiles_differentTiles_extraTileRemoved() {
when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
mController.setTiles();
@@ -400,8 +400,8 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
when(mQSHost.getTiles()).thenReturn(List.of(mQSTile));
mController.setTiles();
- verify(mQSPanel, times(2)).removeTile(any());
- verify(mQSPanel).addTile(any());
+ verify(mQSPanel, times(1)).removeTile(any());
+ verify(mQSPanel, never()).addTile(any());
}
@Test
@@ -418,7 +418,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
}
@Test
- public void setTiles_sameTilesDifferentOrder_removesAndReadds() {
+ public void setTiles_sameTilesDifferentOrder_removesAndReads() {
when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
mController.setTiles();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
index e9714dc524ee..9b61447c8de7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
@@ -31,6 +31,7 @@ import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.res.R
+import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -66,6 +67,7 @@ class RecordIssueTileTest : SysuiTestCase() {
@Mock private lateinit var dialogLauncherAnimator: DialogLaunchAnimator
@Mock private lateinit var dialogFactory: SystemUIDialog.Factory
@Mock private lateinit var dialog: SystemUIDialog
+ @Mock private lateinit var userContextProvider: UserContextProvider
private lateinit var testableLooper: TestableLooper
private lateinit var tile: RecordIssueTile
@@ -91,7 +93,8 @@ class RecordIssueTileTest : SysuiTestCase() {
keyguardDismissUtil,
keyguardStateController,
dialogLauncherAnimator,
- dialogFactory
+ dialogFactory,
+ userContextProvider,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
index bbc59d03ac2b..c5d35245ba7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
@@ -65,7 +65,8 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() {
)
latch = CountDownLatch(1)
- dialog = RecordIssueDialogDelegate(dialogFactory) { latch.countDown() }.createDialog()
+ dialog =
+ RecordIssueDialogDelegate(dialogFactory, mock()) { latch.countDown() }.createDialog()
dialog.show()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 112368895888..b58a41c89a4e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.theme;
+import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
@@ -90,6 +91,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
private static final int USER_SYSTEM = UserHandle.USER_SYSTEM;
private static final int USER_SECONDARY = 10;
+ private static final UserHandle MANAGED_USER_HANDLE = UserHandle.of(100);
+ private static final UserHandle PRIVATE_USER_HANDLE = UserHandle.of(101);
+
@Mock
private JavaAdapter mJavaAdapter;
@Mock
@@ -174,6 +178,14 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
Integer.toHexString(mColorScheme.getSeed() | 0xff000000)));
return overlay;
}
+
+ @VisibleForTesting
+ protected boolean isPrivateProfile(UserHandle userHandle) {
+ if (userHandle.getIdentifier() == PRIVATE_USER_HANDLE.getIdentifier()) {
+ return true;
+ }
+ return false;
+ }
};
mWakefulnessLifecycle.dispatchFinishedWakingUp();
@@ -675,7 +687,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
@Test
public void onProfileAdded_setsTheme() {
mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
+ new Intent(Intent.ACTION_PROFILE_ADDED)
+ .putExtra(Intent.EXTRA_USER, MANAGED_USER_HANDLE));
verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@@ -684,7 +697,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
reset(mDeviceProvisionedController);
when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
+ new Intent(Intent.ACTION_PROFILE_ADDED)
+ .putExtra(Intent.EXTRA_USER, MANAGED_USER_HANDLE));
verify(mThemeOverlayApplier)
.applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@@ -694,11 +708,25 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
reset(mDeviceProvisionedController);
when(mUserManager.isManagedProfile(anyInt())).thenReturn(true);
mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
+ new Intent(Intent.ACTION_PROFILE_ADDED)
+ .putExtra(Intent.EXTRA_USER, MANAGED_USER_HANDLE));
+ verify(mThemeOverlayApplier, never())
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
+ public void onPrivateProfileAdded_ignoresUntilStartComplete() {
+ mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
+ reset(mDeviceProvisionedController);
+ when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
+ mBroadcastReceiver.getValue().onReceive(null,
+ (new Intent(Intent.ACTION_PROFILE_ADDED))
+ .putExtra(Intent.EXTRA_USER, PRIVATE_USER_HANDLE));
verify(mThemeOverlayApplier, never())
.applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
+
@Test
public void onWallpaperColorsChanged_firstEventBeforeUserSetup_shouldBeAccepted() {
// By default, on setup() we make this controller return that the user finished setup
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
index 60fe7d2248e4..140e919d613f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
@@ -2,9 +2,8 @@ package com.android.systemui.user.domain.interactor
import android.content.pm.UserInfo
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_REFACTOR_GET_CURRENT_USER
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.user.data.repository.FakeUserRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
@@ -24,15 +23,12 @@ class SelectedUserInteractorTest : SysuiTestCase() {
@Before
fun setUp() {
userRepository.setUserInfos(USER_INFOS)
- underTest =
- SelectedUserInteractor(
- userRepository,
- FakeFeatureFlagsClassic().apply { set(Flags.REFACTOR_GETCURRENTUSER, true) }
- )
+ underTest = SelectedUserInteractor(userRepository)
}
@Test
fun getSelectedUserIdReturnsId() {
+ mSetFlagsRule.enableFlags(FLAG_REFACTOR_GET_CURRENT_USER)
runBlocking { userRepository.setSelectedUserInfo(USER_INFOS[0]) }
val actualId = underTest.getSelectedUserId()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt
new file mode 100644
index 000000000000..607a4f3e1c0f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.accessibility.data.repository
+
+import android.os.UserHandle
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class FakeColorCorrectionRepository : ColorCorrectionRepository {
+ private val userMap = mutableMapOf<Int, MutableStateFlow<Boolean>>()
+
+ override fun isEnabled(userHandle: UserHandle): StateFlow<Boolean> {
+ return getFlow(userHandle.identifier)
+ }
+
+ override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean {
+ getFlow(userHandle.identifier).value = isEnabled
+ return true
+ }
+
+ /** initializes the flow if already not */
+ private fun getFlow(userId: Int): MutableStateFlow<Boolean> {
+ return userMap.getOrPut(userId) { MutableStateFlow(false) }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt
new file mode 100644
index 000000000000..1c8bd3b58dfe
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt
@@ -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 com.android.systemui.biometrics.data.repository
+
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeBiometricStatusRepository : BiometricStatusRepository {
+ private val _fingerprintAuthenticationReason =
+ MutableStateFlow<AuthenticationReason>(AuthenticationReason.NotRunning)
+ override val fingerprintAuthenticationReason: StateFlow<AuthenticationReason> =
+ _fingerprintAuthenticationReason.asStateFlow()
+
+ fun setFingerprintAuthenticationReason(reason: AuthenticationReason) {
+ _fingerprintAuthenticationReason.value = reason
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
index f84481c55664..ff5179a7042c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
@@ -1,5 +1,6 @@
package com.android.systemui.bouncer.data.repository
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import com.android.systemui.dagger.SysUISingleton
@@ -113,7 +114,9 @@ class FakeKeyguardBouncerRepository @Inject constructor() : KeyguardBouncerRepos
_isBackButtonEnabled.value = isBackButtonEnabled
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
override fun setSideFpsShowing(isShowing: Boolean) {
+ SideFpsControllerRefactor.assertInLegacyMode()
_sideFpsShowing.value = isShowing
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
index c9160efb75a4..1d44929a20f0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
@@ -54,6 +54,11 @@ class FakeDeviceEntryFingerprintAuthRepository @Inject constructor() :
private var _authenticationStatus = MutableStateFlow<FingerprintAuthenticationStatus?>(null)
override val authenticationStatus: Flow<FingerprintAuthenticationStatus>
get() = _authenticationStatus.filterNotNull()
+
+ private var _shouldUpdateIndicatorVisibility = MutableStateFlow(false)
+ override val shouldUpdateIndicatorVisibility: Flow<Boolean>
+ get() = _shouldUpdateIndicatorVisibility
+
fun setAuthenticationStatus(status: FingerprintAuthenticationStatus) {
_authenticationStatus.value = status
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
index 3d8ae1e9801a..3cabf0c07423 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
@@ -27,8 +27,6 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInte
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -57,12 +55,6 @@ object KeyguardDismissInteractorFactory {
keyguardRepository: FakeKeyguardRepository = FakeKeyguardRepository(),
bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
keyguardUpdateMonitor: KeyguardUpdateMonitor = mock(KeyguardUpdateMonitor::class.java),
- featureFlags: FakeFeatureFlagsClassic =
- FakeFeatureFlagsClassic().apply {
- set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, true)
- set(Flags.FULL_SCREEN_USER_SWITCHER, false)
- set(Flags.REFACTOR_GETCURRENTUSER, true)
- },
powerRepository: FakePowerRepository = FakePowerRepository(),
userRepository: FakeUserRepository = FakeUserRepository(),
): WithDependencies {
@@ -98,8 +90,7 @@ object KeyguardDismissInteractorFactory {
PowerInteractorFactory.create(
repository = powerRepository,
)
- val selectedUserInteractor =
- SelectedUserInteractor(repository = userRepository, flags = featureFlags)
+ val selectedUserInteractor = SelectedUserInteractor(repository = userRepository)
return WithDependencies(
trustRepository = trustRepository,
keyguardRepository = keyguardRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt
new file mode 100644
index 000000000000..0357036d907c
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection
+
+import com.android.systemui.accessibility.qs.QSAccessibilityModule
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.qsEventLogger
+
+val Kosmos.qsColorCorrectionTileConfig by
+ Kosmos.Fixture { QSAccessibilityModule.provideColorCorrectionTileConfig(qsEventLogger) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTilePackageUpdatesRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTilePackageUpdatesRepository.kt
index 8f972f52729f..18b3f47e3df7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTilePackageUpdatesRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTilePackageUpdatesRepository.kt
@@ -16,17 +16,20 @@
package com.android.systemui.qs.tiles.impl.custom.data.repository
+import android.os.UserHandle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
class FakeCustomTilePackageUpdatesRepository : CustomTilePackageUpdatesRepository {
- private val mutablePackageChanges = MutableSharedFlow<Unit>()
+ private val mutablePackageChangesForUser = MutableSharedFlow<UserHandle>()
- override val packageChanges: Flow<Unit>
- get() = mutablePackageChanges
+ override fun getPackageChangesForUser(user: UserHandle): Flow<Unit> =
+ mutablePackageChangesForUser.filter { it == user }.map {}
- suspend fun emitPackageChange() {
- mutablePackageChanges.emit(Unit)
+ suspend fun emitPackageChange(user: UserHandle) {
+ mutablePackageChangesForUser.emit(user)
}
}
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 d78bcb93b256..0b41926ed13e 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
@@ -387,7 +387,7 @@ class SceneTestUtils(
}
fun selectedUserInteractor(): SelectedUserInteractor {
- return SelectedUserInteractor(userRepository, featureFlags)
+ return SelectedUserInteractor(userRepository)
}
fun bouncerActionButtonInteractor(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt
index 427f92a7f514..89672f109657 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt
@@ -16,9 +16,7 @@
package com.android.systemui.user.domain.interactor
-import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.user.data.repository.userRepository
-val Kosmos.selectedUserInteractor by
- Kosmos.Fixture { SelectedUserInteractor(userRepository, featureFlagsClassic) }
+val Kosmos.selectedUserInteractor by Kosmos.Fixture { SelectedUserInteractor(userRepository) }
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
index b8cf13b11534..e2488a51bba1 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/Android.bp
@@ -19,6 +19,9 @@ java_library_static {
defaults: [
"platform_service_defaults",
],
+ lint: {
+ error_checks: ["MissingPermissionAnnotation"],
+ },
srcs: [
":services.accessibility-sources",
"//frameworks/base/packages/SettingsLib/RestrictedLockUtils:SettingsLibRestrictedLockUtilsSrc",
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 97d36d443620..1d73843260cb 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -118,6 +118,7 @@ import java.util.Set;
* This class represents an accessibility client - either an AccessibilityService or a UiAutomation.
* It is responsible for behavior common to both types of clients.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub
implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter,
FingerprintGestureDispatcher.FingerprintGestureClient {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 9ddc35ae240b..abcd8e2a2d7e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -57,6 +57,7 @@ import java.util.StringJoiner;
*
* NOTE: This class has to be created and poked only from the main thread.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
class AccessibilityInputFilter extends InputFilter implements EventStreamTransformation {
private static final String TAG = AccessibilityInputFilter.class.getSimpleName();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index edb41639514b..3d8d7b738233 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -195,6 +195,7 @@ import java.util.function.Predicate;
* event dispatch for {@link AccessibilityEvent}s generated across all processes
* on the device. Events are dispatched to {@link AccessibilityService}s.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class AccessibilityManagerService extends IAccessibilityManager.Stub
implements AbstractAccessibilityServiceConnection.SystemSupport,
AccessibilityUserState.ServiceInfoChangeListener,
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 40ca694dddd8..5ebe16115a4b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -65,6 +65,7 @@ import java.util.Set;
* passed to the service it represents as soon it is bound. It also serves as the
* connection for the service.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnection {
private static final String LOG_TAG = "AccessibilityServiceConnection";
diff --git a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
index a525e7c64bc3..b119d7d117cd 100644
--- a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
+++ b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
@@ -34,6 +34,7 @@ import java.util.List;
* If we are stripping and/or replacing the actions from a window, we need to intercept the
* nodes heading back to the service and swap out the actions.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class ActionReplacingCallback extends IAccessibilityInteractionConnectionCallback.Stub {
private static final boolean DEBUG = false;
private static final String LOG_TAG = "ActionReplacingCallback";
diff --git a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
index c9ec16edc54e..e10e87c51d59 100644
--- a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
@@ -33,6 +33,7 @@ import java.util.List;
/**
* Encapsulate fingerprint gesture logic
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallback.Stub
implements Handler.Callback{
private static final int MSG_REGISTER = 1;
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
index ab01fc324ed2..6aa4702ec7d5 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
@@ -64,6 +64,7 @@ import java.util.Set;
*
* TODO(241429275): Initialize this when a proxy is registered.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class ProxyAccessibilityServiceConnection extends AccessibilityServiceConnection {
private static final String LOG_TAG = "ProxyAccessibilityServiceConnection";
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index 53c629a9ed2d..f69104db7c10 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -245,6 +245,7 @@ class UiAutomationManager {
}
}
+ @SuppressWarnings("MissingPermissionAnnotation")
private class UiAutomationService extends AbstractAccessibilityServiceConnection {
private final Handler mMainHandler;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
index e6af54bd937c..e11c36a91830 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
@@ -922,6 +922,7 @@ public class MagnificationConnectionManager implements
disableWindowMagnification(displayId, true);
}
+ @SuppressWarnings("MissingPermissionAnnotation")
private class ConnectionCallback extends IMagnificationConnectionCallback.Stub implements
IBinder.DeathRecipient {
private boolean mExpiredDeathRecipient = false;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
index c63784a79ffd..db5b3133169a 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
@@ -246,6 +246,7 @@ class MagnificationConnectionWrapper {
return new RemoteAnimationCallback(callback, trace);
}
+ @SuppressWarnings("MissingPermissionAnnotation")
private static class RemoteAnimationCallback extends
IRemoteMagnificationAnimationCallback.Stub {
private final MagnificationAnimationCallback mCallback;
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 77a5e3db2aba..a4b28967e3b2 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -72,6 +72,7 @@ import android.content.pm.ServiceInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -559,10 +560,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(appUserId);
} else if (provider.maskedBySuspendedPackage) {
showBadge = mUserManager.hasBadge(appUserId);
- final String suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
+ final UserPackage suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
appInfo.packageName, appUserId);
// TODO(b/281839596): don't rely on platform always meaning suspended by admin.
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+ if (suspendingPackage != null
+ && PLATFORM_PACKAGE_NAME.equals(suspendingPackage.packageName)) {
onClickIntent = mDevicePolicyManagerInternal.createShowAdminSupportIntent(
appUserId, true);
} else {
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index ca6fefdd8245..b5130a1c4cfc 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -29,7 +29,7 @@ flag {
}
flag {
- name: "ignore_invisible_view_group_in_assist_structure"
+ name: "include_invisible_view_group_in_assist_structure"
namespace: "autofill"
description: "Mitigation for autofill providers miscalculating view visibility"
bug: "291795358"
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 23e7ce68c1d0..9fdf5c2d0fc1 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -92,9 +92,10 @@ class CompanionDeviceShellCommand extends ShellCommand {
int userId = getNextIntArgRequired();
String packageName = getNextArgRequired();
String address = getNextArgRequired();
+ String deviceProfile = getNextArg();
final MacAddress macAddress = MacAddress.fromString(address);
mService.createNewAssociation(userId, packageName, macAddress,
- null, null, false);
+ null, deviceProfile, false);
}
break;
@@ -350,7 +351,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
pw.println(" Print this help text.");
pw.println(" list USER_ID");
pw.println(" List all Associations for a user.");
- pw.println(" associate USER_ID PACKAGE MAC_ADDRESS");
+ pw.println(" associate USER_ID PACKAGE MAC_ADDRESS [DEVICE_PROFILE]");
pw.println(" Create a new Association.");
pw.println(" disassociate USER_ID PACKAGE MAC_ADDRESS");
pw.println(" Remove an existing Association.");
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 8dc6537d7e80..0d5cdcbe484c 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -439,6 +439,12 @@ public class VirtualDeviceManagerService extends SystemService {
if (associationInfo == null) {
throw new IllegalArgumentException("No association with ID " + associationId);
}
+ if (!VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES
+ .contains(associationInfo.getDeviceProfile())
+ && Flags.persistentDeviceIdApi()) {
+ throw new IllegalArgumentException("Unsupported CDM Association device profile "
+ + associationInfo.getDeviceProfile() + " for virtual device creation.");
+ }
Objects.requireNonNull(params);
Objects.requireNonNull(activityListener);
Objects.requireNonNull(soundEffectListener);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a0ccbf3acf0a..f5a80d80f271 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -200,6 +200,7 @@ java_library_static {
"notification_flags_lib",
"biometrics_flags_lib",
"am_flags_lib",
+ "com_android_systemui_shared_flags_lib",
"com_android_wm_shell_flags_lib",
"com.android.server.utils_aconfig-java",
"service-jobscheduler-deviceidle.flags-aconfig-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 136692eb90d5..cac2efba1c89 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -289,11 +289,11 @@ public abstract class PackageManagerInternal {
*
* @param suspendedPackage The package that has been suspended.
* @param userId The user for which to check.
- * @return Name of the package that suspended the given package. Returns {@code null} if the
- * given package is not currently suspended and the platform package name - i.e.
- * {@code "android"} - if the package was suspended by a device admin.
+ * @return User id and package name of the package that suspended the given package. Returns
+ * {@code null} if the given package is not currently suspended and the platform package name
+ * - i.e. {@code "android"} - if the package was suspended by a device admin.
*/
- public abstract String getSuspendingPackage(String suspendedPackage, int userId);
+ public abstract UserPackage getSuspendingPackage(String suspendedPackage, int userId);
/**
* Suspend or unsuspend packages upon admin request.
@@ -312,13 +312,13 @@ public abstract class PackageManagerInternal {
* suspended application.
*
* @param suspendedPackage The package that has been suspended.
- * @param suspendingPackage
+ * @param suspendingPackage The package responsible for suspension.
* @param userId The user for which to check.
* @return A {@link SuspendDialogInfo} object describing the dialog to be shown.
*/
@Nullable
public abstract SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
- String suspendingPackage, int userId);
+ UserPackage suspendingPackage, int userId);
/**
* Gets any distraction flags set via
@@ -1168,14 +1168,14 @@ public abstract class PackageManagerInternal {
public abstract void clearBlockUninstallForUser(@UserIdInt int userId);
/**
- * Unsuspends all packages suspended by the given package for the user.
+ * Unsuspends all packages suspended by an admin for the user.
*/
- public abstract void unsuspendForSuspendingPackage(String suspendingPackage, int userId);
+ public abstract void unsuspendAdminSuspendedPackages(int userId);
/**
- * Returns {@code true} if the package is suspending any packages for the user.
+ * Returns {@code true} if an admin is suspending any packages for the user.
*/
- public abstract boolean isSuspendingAnyPackages(String suspendingPackage, int userId);
+ public abstract boolean isAdminSuspendingAnyPackages(int userId);
/**
* Register to listen for loading progress of an installed package.
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 33726d17da62..5a44ac803cb4 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -974,6 +974,7 @@ public final class BatteryService extends SystemService {
unplugBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw);
} break;
case "get": {
+ final int opts = parseOptions(shell);
final String key = shell.getNextArg();
if (key == null) {
pw.println("No property specified");
@@ -1007,11 +1008,17 @@ public final class BatteryService extends SystemService {
break;
case "current_now":
if (batteryServiceSupportCurrentAdbCommand()) {
+ if ((opts & OPTION_FORCE_UPDATE) != 0) {
+ updateHealthInfo();
+ }
pw.println(mHealthInfo.batteryCurrentMicroamps);
}
break;
case "current_average":
if (batteryServiceSupportCurrentAdbCommand()) {
+ if ((opts & OPTION_FORCE_UPDATE) != 0) {
+ updateHealthInfo();
+ }
pw.println(mHealthInfo.batteryCurrentAverageMicroamps);
}
break;
@@ -1125,6 +1132,14 @@ public final class BatteryService extends SystemService {
return 0;
}
+ private void updateHealthInfo() {
+ try {
+ mHealthServiceWrapper.scheduleUpdate();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to update health service data.", e);
+ }
+ }
+
private void setChargerAcOnline(boolean online, boolean forceUpdate) {
if (!mUpdatesStopped) {
copyV1Battery(mLastHealthInfo, mHealthInfo);
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
index c7a560b52a01..9f31f375dafe 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
@@ -226,20 +226,28 @@ public class AmbientContextManagerService extends
List<AmbientContextManagerPerUserService> serviceList =
new ArrayList<>(serviceNames.length);
- if (serviceNames.length == 2) {
+ if (serviceNames.length == 2
+ && !isDefaultService(serviceNames[0])
+ && !isDefaultWearableService(serviceNames[1])) {
Slog.i(TAG, "Not using default services, "
+ "services provided for testing should be exactly two services.");
- if (!isDefaultService(serviceNames[0]) && !isDefaultWearableService(serviceNames[1])) {
- serviceList.add(new DefaultAmbientContextManagerPerUserService(
- this, mLock, resolvedUserId,
- AmbientContextManagerPerUserService.ServiceType.DEFAULT, serviceNames[0]));
- serviceList.add(new WearableAmbientContextManagerPerUserService(
- this, mLock, resolvedUserId,
- AmbientContextManagerPerUserService.ServiceType.WEARABLE,
- serviceNames[1]));
- }
+ serviceList.add(
+ new DefaultAmbientContextManagerPerUserService(
+ this,
+ mLock,
+ resolvedUserId,
+ AmbientContextManagerPerUserService.ServiceType.DEFAULT,
+ serviceNames[0]));
+ serviceList.add(
+ new WearableAmbientContextManagerPerUserService(
+ this,
+ mLock,
+ resolvedUserId,
+ AmbientContextManagerPerUserService.ServiceType.WEARABLE,
+ serviceNames[1]));
return serviceList;
- } else {
+ }
+ if (serviceNames.length > 2) {
Slog.i(TAG, "Incorrect number of services provided for testing.");
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 34cfdfaa7974..d138f24e7dc7 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -896,7 +896,8 @@ public class AudioDeviceInventory {
if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
boolean codecChange = false;
if (btInfo.mProfile == BluetoothProfile.A2DP
- || btInfo.mProfile == BluetoothProfile.LE_AUDIO) {
+ || btInfo.mProfile == BluetoothProfile.LE_AUDIO
+ || btInfo.mProfile == BluetoothProfile.LE_AUDIO_BROADCAST) {
if (di.mDeviceCodecFormat != codec) {
di.mDeviceCodecFormat = codec;
mConnectedDevices.replace(key, di);
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 401dc88669ec..8075618be200 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -324,7 +324,8 @@ public class BtHelper {
// AUDIO_FORMAT_DEFAULT as native audio policy manager expects a specific audio format
// only if audio HW module selection based on format is supported for the device type.
if (!(profile == BluetoothProfile.A2DP
- || (profile == BluetoothProfile.LE_AUDIO && isLeOutput))) {
+ || (isLeOutput && ((profile == BluetoothProfile.LE_AUDIO)
+ || (profile == BluetoothProfile.LE_AUDIO_BROADCAST))))) {
return AudioSystem.AUDIO_FORMAT_DEFAULT;
}
@AudioSystem.AudioFormatNativeEnumForBtCodec int codec =
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 0629e6373b6e..dafea9a199fd 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -36,6 +36,7 @@ import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.ComponentInfoInternal;
@@ -385,6 +386,26 @@ public class AuthService extends SystemService {
}
@Override
+ public void registerAuthenticationStateListener(AuthenticationStateListener listener)
+ throws RemoteException {
+ checkInternalPermission();
+ final IFingerprintService fingerprintService = mInjector.getFingerprintService();
+ if (fingerprintService != null) {
+ fingerprintService.registerAuthenticationStateListener(listener);
+ }
+ }
+
+ @Override
+ public void unregisterAuthenticationStateListener(AuthenticationStateListener listener)
+ throws RemoteException {
+ checkInternalPermission();
+ final IFingerprintService fingerprintService = mInjector.getFingerprintService();
+ if (fingerprintService != null) {
+ fingerprintService.unregisterAuthenticationStateListener(listener);
+ }
+ }
+
+ @Override
public void invalidateAuthenticatorIds(int userId, int fromSensorId,
IInvalidationCallback callback) throws RemoteException {
checkInternalPermission();
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index a47135fd032f..f9568ea9d72b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -27,7 +27,7 @@ import android.hardware.biometrics.AuthenticateOptions;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.os.IBinder;
import android.os.RemoteException;
import android.security.KeyStore;
@@ -430,19 +430,19 @@ public abstract class AuthenticationClient<T, O extends AuthenticateOptions>
return mLockoutTracker;
}
- protected int getShowOverlayReason() {
+ protected int getRequestReason() {
if (isKeyguard()) {
- return BiometricOverlayConstants.REASON_AUTH_KEYGUARD;
+ return BiometricRequestConstants.REASON_AUTH_KEYGUARD;
} else if (isBiometricPrompt()) {
// BP reason always takes precedent over settings, since callers from within
// settings can always invoke BP.
- return BiometricOverlayConstants.REASON_AUTH_BP;
+ return BiometricRequestConstants.REASON_AUTH_BP;
} else if (isSettings()) {
// This is pretty much only for FingerprintManager#authenticate usage from
// FingerprintSettings.
- return BiometricOverlayConstants.REASON_AUTH_SETTINGS;
+ return BiometricRequestConstants.REASON_AUTH_SETTINGS;
} else {
- return BiometricOverlayConstants.REASON_AUTH_OTHER;
+ return BiometricRequestConstants.REASON_AUTH_OTHER;
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java
new file mode 100644
index 000000000000..58635353c780
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java
@@ -0,0 +1,108 @@
+/*
+ * 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.biometrics.sensors;
+
+import android.annotation.NonNull;
+import android.hardware.biometrics.AuthenticationStateListener;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Low-level callback interface between BiometricManager and AuthService. Allows core system
+ * services (e.g. SystemUI) to register and unregister listeners for updates about the current
+ * state of biometric authentication.
+ * @hide */
+public class AuthenticationStateListeners implements IBinder.DeathRecipient {
+
+ private static final String TAG = "AuthenticationStateListeners";
+
+ @NonNull
+ private final CopyOnWriteArrayList<AuthenticationStateListener> mAuthenticationStateListeners =
+ new CopyOnWriteArrayList<>();
+
+ /**
+ * Enables clients to register an AuthenticationStateListener for updates about the current
+ * state of biometric authentication.
+ * @param listener listener to register
+ */
+ public void registerAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ mAuthenticationStateListeners.add(listener);
+ try {
+ listener.asBinder().linkToDeath(this, 0 /* flags */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to link to death", e);
+ }
+ }
+
+ /**
+ * Enables clients to unregister an AuthenticationStateListener.
+ * @param listener listener to register
+ */
+ public void unregisterAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ mAuthenticationStateListeners.remove(listener);
+ }
+
+ /**
+ * Defines behavior in response to authentication starting
+ * @param requestReason reason from [BiometricRequestConstants.RequestReason] for requesting
+ * authentication starting
+ */
+ public void onAuthenticationStarted(int requestReason) {
+ for (AuthenticationStateListener listener: mAuthenticationStateListeners) {
+ try {
+ listener.onAuthenticationStarted(requestReason);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in notifying listener that authentication "
+ + "started", e);
+ }
+ }
+ }
+
+ /**
+ * Defines behavior in response to authentication stopping
+ */
+ public void onAuthenticationStopped() {
+ for (AuthenticationStateListener listener: mAuthenticationStateListeners) {
+ try {
+ listener.onAuthenticationStopped();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in notifying listener that authentication "
+ + "stopped", e);
+ }
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ // Do nothing, handled below
+ }
+
+ @Override
+ public void binderDied(IBinder who) {
+ Slog.w(TAG, "Callback binder died: " + who);
+ if (mAuthenticationStateListeners.removeIf(listener -> listener.asBinder().equals(who))) {
+ Slog.w(TAG, "Removed dead listener for " + who);
+ } else {
+ Slog.w(TAG, "No dead listeners found");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index 483ce75eae98..2c4d30b622ad 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -19,7 +19,7 @@ package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.fingerprint.FingerprintManager;
import android.os.IBinder;
import android.os.RemoteException;
@@ -135,14 +135,14 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> implements En
return true;
}
- protected int getOverlayReasonFromEnrollReason(@FingerprintManager.EnrollReason int reason) {
+ protected int getRequestReasonFromEnrollReason(@FingerprintManager.EnrollReason int reason) {
switch (reason) {
case FingerprintManager.ENROLL_FIND_SENSOR:
- return BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR;
+ return BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR;
case FingerprintManager.ENROLL_ENROLL:
- return BiometricOverlayConstants.REASON_ENROLL_ENROLLING;
+ return BiometricRequestConstants.REASON_ENROLL_ENROLLING;
default:
- return BiometricOverlayConstants.REASON_UNKNOWN;
+ return BiometricRequestConstants.REASON_UNKNOWN;
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
index aeb6b6e2a907..3d20efc88c77 100644
--- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
@@ -16,9 +16,11 @@
package com.android.server.biometrics.sensors;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
@@ -42,6 +44,8 @@ public final class SensorOverlays {
private static final String TAG = "SensorOverlays";
@NonNull private final Optional<IUdfpsOverlayController> mUdfpsOverlayController;
+
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@NonNull private final Optional<ISidefpsController> mSidefpsController;
/**
@@ -58,19 +62,32 @@ public final class SensorOverlays {
}
/**
+ * Create an overlay controller for each modality.
+ *
+ * @param udfpsOverlayController under display fps or null if not present on device
+ */
+ public SensorOverlays(@Nullable IUdfpsOverlayController udfpsOverlayController) {
+ mUdfpsOverlayController = Optional.ofNullable(udfpsOverlayController);
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ mSidefpsController = Optional.empty();
+ }
+
+ /**
* Show the overlay.
*
* @param sensorId sensor id
* @param reason reason for showing
* @param client client performing operation
*/
- public void show(int sensorId, @BiometricOverlayConstants.ShowReason int reason,
+ public void show(int sensorId, @BiometricRequestConstants.RequestReason int reason,
@NonNull AcquisitionClient<?> client) {
- if (mSidefpsController.isPresent()) {
- try {
- mSidefpsController.get().show(sensorId, reason);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when showing the side-fps overlay", e);
+ if (!sidefpsControllerRefactor()) {
+ if (mSidefpsController.isPresent()) {
+ try {
+ mSidefpsController.get().show(sensorId, reason);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when showing the side-fps overlay", e);
+ }
}
}
@@ -98,11 +115,13 @@ public final class SensorOverlays {
* @param sensorId sensor id
*/
public void hide(int sensorId) {
- if (mSidefpsController.isPresent()) {
- try {
- mSidefpsController.get().hide(sensorId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when hiding the side-fps overlay", e);
+ if (!sidefpsControllerRefactor()) {
+ if (mSidefpsController.isPresent()) {
+ try {
+ mSidefpsController.get().hide(sensorId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when hiding the side-fps overlay", e);
+ }
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 769554315b6e..83b306b07c27 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -33,6 +33,7 @@ import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -81,6 +82,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -128,6 +130,8 @@ public class FingerprintService extends SystemService {
private final BiometricStateCallback<ServiceProvider, FingerprintSensorPropertiesInternal>
mBiometricStateCallback;
@NonNull
+ private final AuthenticationStateListeners mAuthenticationStateListeners;
+ @NonNull
private final Handler mHandler;
@NonNull
private final FingerprintServiceRegistry mRegistry;
@@ -891,6 +895,7 @@ public class FingerprintService extends SystemService {
return providers;
});
}
+
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void addAuthenticatorsRegisteredCallback(
@@ -902,6 +907,24 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
+ public void registerAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ super.registerAuthenticationStateListener_enforcePermission();
+
+ mAuthenticationStateListeners.registerAuthenticationStateListener(listener);
+ }
+
+ @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
+ @Override
+ public void unregisterAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ super.unregisterAuthenticationStateListener_enforcePermission();
+
+ mAuthenticationStateListeners.unregisterAuthenticationStateListener(listener);
+ }
+
+ @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
+ @Override
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
super.registerBiometricStateListener_enforcePermission();
@@ -957,6 +980,7 @@ public class FingerprintService extends SystemService {
}
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
@@ -1014,6 +1038,7 @@ public class FingerprintService extends SystemService {
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mBiometricStateCallback = new BiometricStateCallback<>(UserManager.get(context));
+ mAuthenticationStateListeners = new AuthenticationStateListeners();
mFingerprintProvider = fingerprintProvider != null ? fingerprintProvider :
(name) -> {
final String fqName = IFingerprint.DESCRIPTOR + "/" + name;
@@ -1022,9 +1047,9 @@ public class FingerprintService extends SystemService {
if (fp != null) {
try {
return new FingerprintProvider(getContext(),
- mBiometricStateCallback, fp.getSensorProps(), name,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
- mBiometricContext);
+ mBiometricStateCallback, mAuthenticationStateListeners,
+ fp.getSensorProps(), name, mLockoutResetDispatcher,
+ mGestureAvailabilityDispatcher, mBiometricContext);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
}
@@ -1086,13 +1111,13 @@ public class FingerprintService extends SystemService {
Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
UserHandle.USER_CURRENT) != 0) {
fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(),
- mBiometricStateCallback, hidlSensor,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
+ mBiometricStateCallback, mAuthenticationStateListeners,
+ hidlSensor, mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
BiometricContext.getInstance(getContext()));
} else {
fingerprint21 = Fingerprint21.newInstance(getContext(),
- mBiometricStateCallback, hidlSensor, mHandler,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ mBiometricStateCallback, mAuthenticationStateListeners, hidlSensor,
+ mHandler, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
providers.add(fingerprint21);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index a15d1a4df39f..fc37d7020a21 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -135,6 +135,7 @@ public interface ServiceProvider extends
void onPowerPressed();
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/**
* Sets side-fps controller
* @param controller side-fps controller
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 337c3c299e54..29c5a3de3a80 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
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
@@ -48,6 +50,7 @@ import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -84,6 +87,7 @@ public class FingerprintAuthenticationClient
private final int mSkipWaitForPowerVendorAcquireMessage;
private final long mFingerUpIgnoresPower = 500;
private final AuthSessionCoordinator mAuthSessionCoordinator;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
@Nullable
private ICancellationSignal mCancellationSignal;
private boolean mIsPointerDown;
@@ -110,7 +114,9 @@ public class FingerprintAuthenticationClient
boolean isStrongBiometric,
@Nullable TaskStackListener taskStackListener,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull Handler handler,
@@ -136,7 +142,12 @@ public class FingerprintAuthenticationClient
false /* shouldVibrate */,
biometricStrength);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
mSensorProps = sensorProps;
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
mHandler = handler;
@@ -216,6 +227,9 @@ public class FingerprintAuthenticationClient
if (authenticated) {
mState = STATE_STOPPED;
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
} else {
mState = STATE_STARTED_PAUSED_ATTEMPTED;
}
@@ -241,6 +255,9 @@ public class FingerprintAuthenticationClient
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
onErrorInternal(errorCode, 0 /* vendorCode */, false /* finish */);
cancel();
}
@@ -266,11 +283,17 @@ public class FingerprintAuthenticationClient
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getShowOverlayReason(), this);
+ mSensorOverlays.show(getSensorId(), getRequestReason(), this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(getRequestReason());
+ }
try {
mCancellationSignal = doAuthenticate();
@@ -280,6 +303,9 @@ public class FingerprintAuthenticationClient
BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -323,6 +349,9 @@ public class FingerprintAuthenticationClient
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
unsubscribeBiometricContext();
if (mCancellationSignal != null) {
@@ -423,6 +452,9 @@ public class FingerprintAuthenticationClient
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
@@ -450,6 +482,9 @@ public class FingerprintAuthenticationClient
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index e2413ee1c016..e58e5ae117b5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -16,10 +16,12 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -66,7 +68,12 @@ public class FingerprintDetectClient extends AcquisitionClient<AidlSession>
true /* shouldVibrate */, biometricLogger, biometricContext);
setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController*/);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(
+ udfpsOverlayController, null /* sideFpsController */);
+ }
mOptions = options;
}
@@ -93,7 +100,7 @@ public class FingerprintDetectClient extends AcquisitionClient<AidlSession>
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), BiometricOverlayConstants.REASON_AUTH_KEYGUARD,
+ mSensorOverlays.show(getSensorId(), BiometricRequestConstants.REASON_AUTH_KEYGUARD,
this);
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 06550d8b4fce..c0761ed8f32b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -42,6 +44,7 @@ import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -65,6 +68,7 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
@NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
private final @FingerprintManager.EnrollReason int mEnrollReason;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
@Nullable private ICancellationSignal mCancellationSignal;
private final int mMaxTemplatesPerUser;
private boolean mIsPointerDown;
@@ -80,15 +84,18 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
}
}
- public FingerprintEnrollClient(@NonNull Context context,
- @NonNull Supplier<AidlSession> lazyDaemon, @NonNull IBinder token, long requestId,
+ public FingerprintEnrollClient(
+ @NonNull Context context, @NonNull Supplier<AidlSession> lazyDaemon,
+ @NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
int maxTemplatesPerUser, @FingerprintManager.EnrollReason int enrollReason) {
// UDFPS haptics occur when an image is acquired (instead of when the result is known)
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
@@ -96,7 +103,13 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
logger, biometricContext);
setRequestId(requestId);
mSensorProps = sensorProps;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
+
mMaxTemplatesPerUser = maxTemplatesPerUser;
mALSProbeCallback = getLogger().getAmbientLightProbe(true /* startWithClient */);
@@ -130,7 +143,11 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
if (remaining == 0) {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
+
}
@Override
@@ -159,8 +176,10 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
@Override
public void onError(int errorCode, int vendorCode) {
super.onError(errorCode, vendorCode);
-
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
@Override
@@ -171,8 +190,12 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason),
+ mSensorOverlays.show(getSensorId(), getRequestReasonFromEnrollReason(mEnrollReason),
this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(
+ getRequestReasonFromEnrollReason(mEnrollReason));
+ }
BiometricNotificationUtils.cancelBadCalibrationNotification(getContext());
try {
@@ -210,6 +233,10 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
+
unsubscribeBiometricContext();
if (mCancellationSignal != null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 9985b06833c9..032ab87196f8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -64,6 +64,7 @@ import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -108,6 +109,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@NonNull
private final BiometricStateCallback mBiometricStateCallback;
@NonNull
+ private final AuthenticationStateListeners mAuthenticationStateListeners;
+ @NonNull
private final String mHalInstanceName;
@NonNull
private final Handler mHandler;
@@ -122,6 +125,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@NonNull private final BiometricContext mBiometricContext;
@Nullable private IFingerprint mDaemon;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable private ISidefpsController mSidefpsController;
private AuthSessionCoordinator mAuthSessionCoordinator;
@Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector;
@@ -157,16 +161,19 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
public FingerprintProvider(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull SensorProps[] props, @NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext) {
- this(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher,
- gestureAvailabilityDispatcher, biometricContext, null /* daemon */);
+ this(context, biometricStateCallback, authenticationStateListeners, props, halInstanceName,
+ lockoutResetDispatcher, gestureAvailabilityDispatcher, biometricContext,
+ null /* daemon */);
}
@VisibleForTesting FingerprintProvider(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull SensorProps[] props, @NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@@ -174,6 +181,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
IFingerprint daemon) {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
+ mAuthenticationStateListeners = authenticationStateListeners;
mHalInstanceName = halInstanceName;
mFingerprintSensors = new SensorList<>(ActivityManager.getService());
mHandler = new Handler(Looper.getMainLooper());
@@ -434,7 +442,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mBiometricContext,
mFingerprintSensors.get(sensorId).getSensorProperties(),
mUdfpsOverlayController, mSidefpsController,
- maxTemplatesPerUser, enrollReason);
+ mAuthenticationStateListeners, maxTemplatesPerUser, enrollReason);
scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback(
mBiometricStateCallback, new ClientMonitorCallback() {
@Override
@@ -498,7 +506,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mBiometricContext, isStrongBiometric,
mTaskStackListener,
mUdfpsOverlayController, mSidefpsController,
- allowBackgroundAuthentication,
+ mAuthenticationStateListeners, allowBackgroundAuthentication,
mFingerprintSensors.get(sensorId).getSensorProperties(), mHandler,
Utils.getCurrentStrength(sensorId),
SystemClock.elapsedRealtimeClock(),
@@ -732,6 +740,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
}
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
mSidefpsController = controller;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 8bfa560b8031..d3cecd0e34c7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -68,6 +68,7 @@ import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -115,6 +116,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
final Context mContext;
@NonNull private final BiometricStateCallback mBiometricStateCallback;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private final ActivityTaskManager mActivityTaskManager;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
private final BiometricScheduler mScheduler;
@@ -128,6 +130,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@Nullable private IBiometricsFingerprint mDaemon;
@NonNull private final HalResultController mHalResultController;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
+
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable private ISidefpsController mSidefpsController;
@NonNull private final BiometricContext mBiometricContext;
@Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector;
@@ -330,6 +334,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@VisibleForTesting
Fingerprint21(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler,
@NonNull Handler handler,
@@ -338,6 +343,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@NonNull BiometricContext biometricContext) {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
+ mAuthenticationStateListeners = authenticationStateListeners;
mBiometricContext = biometricContext;
mSensorProperties = sensorProps;
@@ -378,6 +384,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
public static Fingerprint21 newInstance(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@@ -388,8 +395,9 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
gestureAvailabilityDispatcher);
final HalResultController controller = new HalResultController(sensorProps.sensorId,
context, handler, scheduler);
- return new Fingerprint21(context, biometricStateCallback, sensorProps, scheduler, handler,
- lockoutResetDispatcher, controller, BiometricContext.getInstance(context));
+ return new Fingerprint21(context, biometricStateCallback, authenticationStateListeners,
+ sensorProps, scheduler, handler, lockoutResetDispatcher, controller,
+ BiometricContext.getInstance(context));
}
@Override
@@ -719,7 +727,10 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mSensorProperties.sensorId,
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
- mBiometricContext, mUdfpsOverlayController, mSidefpsController, enrollReason);
+ mBiometricContext, mUdfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ mSidefpsController,
+ mAuthenticationStateListeners, enrollReason);
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
@@ -761,10 +772,14 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
BiometricsProtoEnums.CLIENT_UNKNOWN,
mAuthenticationStatsCollector),
mBiometricContext, null /* sensorProps */,
- mUdfpsOverlayController, mSidefpsController,
+ mUdfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ mSidefpsController,
+ mAuthenticationStateListeners,
mContext.getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser),
enrollReason);
+
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
@@ -880,6 +895,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mBiometricContext, isStrongBiometric,
mTaskStackListener,
mUdfpsOverlayController, mSidefpsController,
+ mAuthenticationStateListeners,
allowBackgroundAuthentication, mSensorProperties, mHandler,
Utils.getCurrentStrength(mSensorId), null /* clock */, mLockoutTracker);
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
@@ -898,6 +914,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mBiometricContext, isStrongBiometric,
mTaskStackListener, mLockoutTracker,
mUdfpsOverlayController, mSidefpsController,
+ mAuthenticationStateListeners,
allowBackgroundAuthentication, mSensorProperties,
Utils.getCurrentStrength(mSensorId));
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
@@ -1123,6 +1140,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mUdfpsOverlayController = controller;
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
mSidefpsController = controller;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index c1a9370b5423..88dae6fcc453 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -41,6 +41,7 @@ import android.util.SparseBooleanArray;
import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -248,6 +249,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
public static Fingerprint21UdfpsMock newInstance(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@@ -259,8 +261,9 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
new TestableBiometricScheduler(TAG, handler, gestureAvailabilityDispatcher);
final MockHalResultController controller =
new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
- return new Fingerprint21UdfpsMock(context, biometricStateCallback, sensorProps, scheduler,
- handler, lockoutResetDispatcher, controller, biometricContext);
+ return new Fingerprint21UdfpsMock(context, biometricStateCallback,
+ authenticationStateListeners, sensorProps, scheduler, handler,
+ lockoutResetDispatcher, controller, biometricContext);
}
private static abstract class FakeFingerRunnable implements Runnable {
@@ -388,14 +391,15 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
private Fingerprint21UdfpsMock(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull TestableBiometricScheduler scheduler,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull MockHalResultController controller,
@NonNull BiometricContext biometricContext) {
- super(context, biometricStateCallback, sensorProps, scheduler, handler,
- lockoutResetDispatcher, controller, biometricContext);
+ super(context, biometricStateCallback, authenticationStateListeners, sensorProps, scheduler,
+ handler, lockoutResetDispatcher, controller, biometricContext);
mScheduler = scheduler;
mScheduler.init(this);
mHandler = handler;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 9966e910d502..4c1d4d6d6d12 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.hidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
@@ -40,6 +42,7 @@ import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -68,6 +71,7 @@ class FingerprintAuthenticationClient
@NonNull private final SensorOverlays mSensorOverlays;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
@NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private boolean mIsPointerDown;
@@ -81,7 +85,9 @@ class FingerprintAuthenticationClient
@NonNull TaskStackListener taskStackListener,
@NonNull LockoutFrameworkImpl lockoutTracker,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@Authenticators.Types int sensorStrength) {
@@ -91,7 +97,12 @@ class FingerprintAuthenticationClient
false /* shouldVibrate */, sensorStrength);
setRequestId(requestId);
mLockoutFrameworkImpl = lockoutTracker;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
mSensorProps = sensorProps;
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
}
@@ -128,6 +139,9 @@ class FingerprintAuthenticationClient
mState = STATE_STOPPED;
resetFailedAttempts(getTargetUserId());
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
} else {
mState = STATE_STARTED_PAUSED_ATTEMPTED;
final @LockoutTracker.LockoutMode int lockoutMode =
@@ -141,6 +155,9 @@ class FingerprintAuthenticationClient
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
onErrorInternal(errorCode, 0 /* vendorCode */, false /* finish */);
cancel();
}
@@ -156,6 +173,9 @@ class FingerprintAuthenticationClient
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
private void resetFailedAttempts(int userId) {
@@ -205,7 +225,10 @@ class FingerprintAuthenticationClient
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getShowOverlayReason(), this);
+ mSensorOverlays.show(getSensorId(), getRequestReason(), this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(getRequestReason());
+ }
try {
// GroupId was never used. In fact, groupId is always the same as userId.
@@ -215,6 +238,9 @@ class FingerprintAuthenticationClient
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -222,6 +248,9 @@ class FingerprintAuthenticationClient
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
try {
getFreshDaemon().cancel();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 0d7f9f23e0e1..6e029d2268e2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -16,12 +16,14 @@
package com.android.server.biometrics.sensors.fingerprint.hidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricFingerprintConstants;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
@@ -71,7 +73,12 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
options.getOpPackageName(), 0 /* cookie */, options.getSensorId(),
true /* shouldVibrate */, biometricLogger, biometricContext);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController */);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(
+ udfpsOverlayController, null /* sideFpsController */);
+ }
mIsStrongBiometric = isStrongBiometric;
}
@@ -97,7 +104,7 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), BiometricOverlayConstants.REASON_AUTH_KEYGUARD,
+ mSensorOverlays.show(getSensorId(), BiometricRequestConstants.REASON_AUTH_KEYGUARD,
this);
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 382e7e2121f4..26332ff6893c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.hidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -34,6 +36,7 @@ import android.util.Slog;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -58,22 +61,31 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@NonNull private final SensorOverlays mSensorOverlays;
private final @FingerprintManager.EnrollReason int mEnrollReason;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private boolean mIsPointerDown;
- FingerprintEnrollClient(@NonNull Context context,
- @NonNull Supplier<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
- long requestId, @NonNull ClientMonitorCallbackConverter listener, int userId,
+ FingerprintEnrollClient(
+ @NonNull Context context, @NonNull Supplier<IBiometricsFingerprint> lazyDaemon,
+ @NonNull IBinder token, long requestId,
+ @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int timeoutSec, int sensorId,
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@FingerprintManager.EnrollReason int enrollReason) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, sensorId, true /* shouldVibrate */, biometricLogger,
biometricContext);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
mEnrollReason = enrollReason;
if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
@@ -110,8 +122,12 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason),
+ mSensorOverlays.show(getSensorId(), getRequestReasonFromEnrollReason(mEnrollReason),
this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(
+ getRequestReasonFromEnrollReason(mEnrollReason));
+ }
BiometricNotificationUtils.cancelBadCalibrationNotification(getContext());
try {
@@ -122,6 +138,9 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -129,6 +148,9 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
try {
getFreshDaemon().cancel();
@@ -149,6 +171,9 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
if (remaining == 0) {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
}
@@ -170,6 +195,9 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
super.onError(errorCode, vendorCode);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
@Override
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index dff14b5fbdd0..6ec6a123a4e7 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -327,7 +327,7 @@ public final class DeviceStateManagerService extends SystemService {
Optional<DeviceState> getOverrideState() {
synchronized (mLock) {
if (mActiveOverride.isPresent()) {
- return getStateLocked(mActiveOverride.get().getRequestedState());
+ return getStateLocked(mActiveOverride.get().getRequestedStateIdentifier());
}
return Optional.empty();
}
@@ -342,7 +342,7 @@ public final class DeviceStateManagerService extends SystemService {
Optional<DeviceState> getOverrideBaseState() {
synchronized (mLock) {
if (mActiveBaseStateOverride.isPresent()) {
- return getStateLocked(mActiveBaseStateOverride.get().getRequestedState());
+ return getStateLocked(mActiveBaseStateOverride.get().getRequestedStateIdentifier());
}
return Optional.empty();
}
@@ -499,6 +499,7 @@ public final class DeviceStateManagerService extends SystemService {
* @return {@code true} if the pending state has changed as a result of this call, {@code false}
* otherwise.
*/
+ @GuardedBy("mLock")
private boolean updatePendingStateLocked() {
if (mPendingState.isPresent()) {
// Have pending state, can not configure a new state until the state is committed.
@@ -507,7 +508,8 @@ public final class DeviceStateManagerService extends SystemService {
final DeviceState stateToConfigure;
if (mActiveOverride.isPresent()) {
- stateToConfigure = getStateLocked(mActiveOverride.get().getRequestedState()).get();
+ stateToConfigure = getStateLocked(
+ mActiveOverride.get().getRequestedStateIdentifier()).get();
} else if (mBaseState.isPresent()
&& isSupportedStateLocked(mBaseState.get().getIdentifier())) {
// Base state could have recently become unsupported after a change in supported states.
@@ -599,7 +601,7 @@ public final class DeviceStateManagerService extends SystemService {
// requested state is committed.
OverrideRequest activeRequest = mActiveOverride.orElse(null);
if (activeRequest != null
- && activeRequest.getRequestedState() == newState.getIdentifier()) {
+ && activeRequest.getRequestedStateIdentifier() == newState.getIdentifier()) {
ProcessRecord processRecord = mProcessRecords.get(activeRequest.getPid());
if (processRecord != null) {
processRecord.notifyRequestActiveAsync(activeRequest.getToken());
@@ -666,21 +668,21 @@ public final class DeviceStateManagerService extends SystemService {
case STATUS_ACTIVE:
mActiveOverride = Optional.of(request);
mDeviceStateNotificationController.showStateActiveNotificationIfNeeded(
- request.getRequestedState(), request.getUid());
+ request.getRequestedStateIdentifier(), request.getUid());
break;
case STATUS_CANCELED:
if (mActiveOverride.isPresent() && mActiveOverride.get() == request) {
mActiveOverride = Optional.empty();
mDeviceStateNotificationController.cancelNotification(
- request.getRequestedState());
+ request.getRequestedStateIdentifier());
if ((flags & FLAG_THERMAL_CRITICAL) == FLAG_THERMAL_CRITICAL) {
mDeviceStateNotificationController
.showThermalCriticalNotificationIfNeeded(
- request.getRequestedState());
+ request.getRequestedStateIdentifier());
} else if ((flags & FLAG_POWER_SAVE_ENABLED) == FLAG_POWER_SAVE_ENABLED) {
mDeviceStateNotificationController
.showPowerSaveNotificationIfNeeded(
- request.getRequestedState());
+ request.getRequestedStateIdentifier());
}
}
break;
@@ -723,7 +725,7 @@ public final class DeviceStateManagerService extends SystemService {
*/
@GuardedBy("mLock")
private void enableBaseStateRequestLocked(OverrideRequest request) {
- setBaseState(request.getRequestedState());
+ setBaseState(request.getRequestedStateIdentifier());
mActiveBaseStateOverride = Optional.of(request);
ProcessRecord processRecord = mProcessRecords.get(request.getPid());
processRecord.notifyRequestActiveAsync(request.getToken());
@@ -762,6 +764,11 @@ public final class DeviceStateManagerService extends SystemService {
synchronized (mLock) {
mProcessRecords.remove(processRecord.mPid);
mOverrideRequestController.handleProcessDied(processRecord.mPid);
+
+ if (shouldCancelOverrideRequestWhenRequesterNotOnTop()) {
+ OverrideRequest request = mActiveOverride.get();
+ mOverrideRequestController.cancelRequest(request);
+ }
}
}
@@ -787,7 +794,7 @@ public final class DeviceStateManagerService extends SystemService {
}
OverrideRequest request = new OverrideRequest(token, callingPid, callingUid,
- state, flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ deviceState.get(), flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
// If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay
if (!hasControlDeviceStatePermission && mRearDisplayState != null
@@ -848,7 +855,7 @@ public final class DeviceStateManagerService extends SystemService {
}
OverrideRequest request = new OverrideRequest(token, callingPid, callingUid,
- state, flags, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ deviceState.get(), flags, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mOverrideRequestController.addBaseStateRequest(request);
}
}
@@ -1318,7 +1325,7 @@ public final class DeviceStateManagerService extends SystemService {
if (mActiveOverride.isEmpty()) {
return false;
}
- int identifier = mActiveOverride.get().getRequestedState();
+ int identifier = mActiveOverride.get().getRequestedStateIdentifier();
DeviceState deviceState = mDeviceStates.get(identifier);
return deviceState.hasFlag(DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
}
diff --git a/services/core/java/com/android/server/devicestate/OverrideRequest.java b/services/core/java/com/android/server/devicestate/OverrideRequest.java
index 74cf184e826e..20485c1ac102 100644
--- a/services/core/java/com/android/server/devicestate/OverrideRequest.java
+++ b/services/core/java/com/android/server/devicestate/OverrideRequest.java
@@ -17,6 +17,7 @@
package com.android.server.devicestate;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.hardware.devicestate.DeviceStateRequest;
import android.os.IBinder;
@@ -32,7 +33,8 @@ final class OverrideRequest {
private final IBinder mToken;
private final int mPid;
private final int mUid;
- private final int mRequestedState;
+ @NonNull
+ private final DeviceState mRequestedState;
@DeviceStateRequest.RequestFlags
private final int mFlags;
@OverrideRequestType
@@ -69,7 +71,7 @@ final class OverrideRequest {
@Retention(RetentionPolicy.SOURCE)
public @interface OverrideRequestType {}
- OverrideRequest(IBinder token, int pid, int uid, int requestedState,
+ OverrideRequest(IBinder token, int pid, int uid, @NonNull DeviceState requestedState,
@DeviceStateRequest.RequestFlags int flags, @OverrideRequestType int requestType) {
mToken = token;
mPid = pid;
@@ -91,10 +93,15 @@ final class OverrideRequest {
return mUid;
}
- int getRequestedState() {
+ @NonNull
+ DeviceState getRequestedDeviceState() {
return mRequestedState;
}
+ int getRequestedStateIdentifier() {
+ return mRequestedState.getIdentifier();
+ }
+
@DeviceStateRequest.RequestFlags
int getFlags() {
return mFlags;
diff --git a/services/core/java/com/android/server/devicestate/OverrideRequestController.java b/services/core/java/com/android/server/devicestate/OverrideRequestController.java
index 46f0bc0d9805..f5f2fa8cabdc 100644
--- a/services/core/java/com/android/server/devicestate/OverrideRequestController.java
+++ b/services/core/java/com/android/server/devicestate/OverrideRequestController.java
@@ -204,6 +204,12 @@ final class OverrideRequestController {
}
if (mRequest != null && mRequest.getPid() == pid) {
+ if (mRequest.getRequestedDeviceState().hasFlag(
+ DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP)) {
+ cancelCurrentRequestLocked();
+ return;
+ }
+
if (mStickyRequestsAllowed) {
// Do not cancel the requests now because sticky requests are allowed. These
// requests will be cancelled on a call to cancelStickyRequests().
@@ -219,7 +225,7 @@ final class OverrideRequestController {
* listener of all changes to request status as a result of this change.
*/
void handleBaseStateChanged(int state) {
- if (mBaseStateRequest != null && state != mBaseStateRequest.getRequestedState()) {
+ if (mBaseStateRequest != null && state != mBaseStateRequest.getRequestedStateIdentifier()) {
cancelBaseStateOverrideRequest();
}
if (mRequest == null) {
@@ -246,11 +252,12 @@ final class OverrideRequestController {
flags |= isThermalCritical ? FLAG_THERMAL_CRITICAL : 0;
flags |= isPowerSaveEnabled ? FLAG_POWER_SAVE_ENABLED : 0;
if (mBaseStateRequest != null && !contains(newSupportedStates,
- mBaseStateRequest.getRequestedState())) {
+ mBaseStateRequest.getRequestedStateIdentifier())) {
cancelCurrentBaseStateRequestLocked(flags);
}
- if (mRequest != null && !contains(newSupportedStates, mRequest.getRequestedState())) {
+ if (mRequest != null && !contains(newSupportedStates,
+ mRequest.getRequestedStateIdentifier())) {
cancelCurrentRequestLocked(flags);
}
}
@@ -262,7 +269,7 @@ final class OverrideRequestController {
pw.println("Override Request active: " + requestActive);
if (requestActive) {
pw.println("Request: mPid=" + overrideRequest.getPid()
- + ", mRequestedState=" + overrideRequest.getRequestedState()
+ + ", mRequestedState=" + overrideRequest.getRequestedStateIdentifier()
+ ", mFlags=" + overrideRequest.getFlags()
+ ", mStatus=" + statusToString(STATUS_ACTIVE));
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 80c3a270efdf..b54289321e89 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -583,8 +583,8 @@ public class AutomaticBrightnessController {
pw.println(" mCurrentLightSensorRate=" + mCurrentLightSensorRate);
pw.println(" mAmbientLux=" + mAmbientLux);
pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
- pw.println(" mPreThesholdLux=" + mPreThresholdLux);
- pw.println(" mPreThesholdBrightness=" + mPreThresholdBrightness);
+ pw.println(" mPreThresholdLux=" + mPreThresholdLux);
+ pw.println(" mPreThresholdBrightness=" + mPreThresholdBrightness);
pw.println(" mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold);
pw.println(" mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold);
pw.println(" mScreenBrighteningThreshold=" + mScreenBrighteningThreshold);
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index bd5e189a5404..aa7f07d24dbf 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -93,6 +93,10 @@ public class DisplayManagerFlags {
Flags.FLAG_ENABLE_EXTERNAL_VSYNC_PROXIMITY_VOTE,
Flags::enableExternalVsyncProximityVote);
+ private final FlagState mVsyncLowPowerVote = new FlagState(
+ Flags.FLAG_ENABLE_VSYNC_LOW_POWER_VOTE,
+ Flags::enableVsyncLowPowerVote);
+
private final FlagState mBrightnessWearBedtimeModeClamperFlagState = new FlagState(
Flags.FLAG_BRIGHTNESS_WEAR_BEDTIME_MODE_CLAMPER,
Flags::brightnessWearBedtimeModeClamper);
@@ -125,7 +129,6 @@ public class DisplayManagerFlags {
return mPowerThrottlingClamperFlagState.isEnabled();
}
-
/**
* Returns whether adaptive tone improvements are enabled
*/
@@ -198,6 +201,10 @@ public class DisplayManagerFlags {
return mVsyncProximityVote.isEnabled();
}
+ public boolean isVsyncLowPowerVoteEnabled() {
+ return mVsyncLowPowerVote.isEnabled();
+ }
+
public boolean isBrightnessWearBedtimeModeClamperEnabled() {
return mBrightnessWearBedtimeModeClamperFlagState.isEnabled();
}
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 7a723a3290a9..04ecbb9e08ad 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -130,6 +130,14 @@ flag {
}
flag {
+ name: "enable_vsync_low_power_vote"
+ namespace: "display_manager"
+ description: "Feature flag for vsync low power vote"
+ bug: "314920284"
+ is_fixed_read_only: true
+}
+
+flag {
name: "brightness_wear_bedtime_mode_clamper"
namespace: "display_manager"
description: "Feature flag for the Wear Bedtime mode brightness clamper"
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index f7b540bc3753..6e503cbd68f3 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -179,7 +179,7 @@ public class DisplayModeDirector {
private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled;
- private final boolean mVsyncProximityVoteEnabled;
+ private final boolean mDvrrSupported;
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
@@ -190,6 +190,8 @@ public class DisplayModeDirector {
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
@NonNull Injector injector,
@NonNull DisplayManagerFlags displayManagerFlags) {
+ mDvrrSupported = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_supportsDvrr);
mIsDisplayResolutionRangeVotingEnabled = displayManagerFlags
.isDisplayResolutionRangeVotingEnabled();
mIsUserPreferredModeVoteEnabled = displayManagerFlags.isUserPreferredModeVoteEnabled();
@@ -199,7 +201,6 @@ public class DisplayModeDirector {
.isDisplaysRefreshRatesSynchronizationEnabled();
mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags
.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled();
- mVsyncProximityVoteEnabled = displayManagerFlags.isVsyncProximityVoteEnabled();
mContext = context;
mHandler = new DisplayModeDirectorHandler(handler.getLooper());
mInjector = injector;
@@ -208,7 +209,8 @@ public class DisplayModeDirector {
mAppRequestObserver = new AppRequestObserver();
mConfigParameterProvider = new DeviceConfigParameterProvider(injector.getDeviceConfig());
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
- mSettingsObserver = new SettingsObserver(context, handler);
+ mSettingsObserver = new SettingsObserver(context, handler, mDvrrSupported,
+ displayManagerFlags);
mBrightnessObserver = new BrightnessObserver(context, handler, injector);
mDefaultDisplayDeviceConfig = null;
mUdfpsObserver = new UdfpsObserver();
@@ -290,7 +292,7 @@ public class DisplayModeDirector {
List<Display.Mode> availableModes = new ArrayList<>();
availableModes.add(defaultMode);
VoteSummary primarySummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled,
- mVsyncProximityVoteEnabled, mLoggingEnabled, mSupportsFrameRateOverride);
+ mDvrrSupported, mLoggingEnabled, mSupportsFrameRateOverride);
int lowestConsideredPriority = Vote.MIN_PRIORITY;
int highestConsideredPriority = Vote.MAX_PRIORITY;
@@ -330,7 +332,7 @@ public class DisplayModeDirector {
}
VoteSummary appRequestSummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled,
- mVsyncProximityVoteEnabled, mLoggingEnabled, mSupportsFrameRateOverride);
+ mDvrrSupported, mLoggingEnabled, mSupportsFrameRateOverride);
appRequestSummary.applyVotes(votes,
Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF,
@@ -818,13 +820,17 @@ public class DisplayModeDirector {
private final Uri mMatchContentFrameRateSetting =
Settings.Secure.getUriFor(Settings.Secure.MATCH_CONTENT_FRAME_RATE);
+ private final boolean mVsynLowPowerVoteEnabled;
+
private final Context mContext;
private float mDefaultPeakRefreshRate;
private float mDefaultRefreshRate;
- SettingsObserver(@NonNull Context context, @NonNull Handler handler) {
+ SettingsObserver(@NonNull Context context, @NonNull Handler handler, boolean dvrrSupported,
+ DisplayManagerFlags flags) {
super(handler);
mContext = context;
+ mVsynLowPowerVoteEnabled = dvrrSupported && flags.isVsyncLowPowerVoteEnabled();
// We don't want to load from the DeviceConfig while constructing since this leads to
// a spike in the latency of DisplayManagerService startup. This happens because
// reading from the DeviceConfig is an intensive IO operation and having it in the
@@ -936,7 +942,14 @@ public class DisplayModeDirector {
boolean inLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE, 0 /*default*/) != 0;
final Vote vote;
- if (inLowPowerMode) {
+ if (inLowPowerMode && mVsynLowPowerVoteEnabled) {
+ vote = Vote.forSupportedModes(List.of(
+ new SupportedModesVote.SupportedMode(/* peakRefreshRate= */ 60f,
+ /* vsyncRate= */ 240f),
+ new SupportedModesVote.SupportedMode(/* peakRefreshRate= */ 60f,
+ /* vsyncRate= */ 60f)
+ ));
+ } else if (inLowPowerMode) {
vote = Vote.forRenderFrameRates(0f, 60f);
} else {
vote = null;
diff --git a/services/core/java/com/android/server/display/mode/Vote.java b/services/core/java/com/android/server/display/mode/Vote.java
index aa44566f6d99..8f3957011b59 100644
--- a/services/core/java/com/android/server/display/mode/Vote.java
+++ b/services/core/java/com/android/server/display/mode/Vote.java
@@ -166,6 +166,10 @@ interface Vote {
return new BaseModeRefreshRateVote(baseModeRefreshRate);
}
+ static Vote forSupportedModes(List<SupportedModesVote.SupportedMode> supportedModes) {
+ return new SupportedModesVote(supportedModes);
+ }
+
static String priorityToString(int priority) {
switch (priority) {
case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE:
diff --git a/services/core/java/com/android/server/display/mode/VoteSummary.java b/services/core/java/com/android/server/display/mode/VoteSummary.java
index 99f414267dee..5fc36b589d38 100644
--- a/services/core/java/com/android/server/display/mode/VoteSummary.java
+++ b/services/core/java/com/android/server/display/mode/VoteSummary.java
@@ -43,14 +43,14 @@ final class VoteSummary {
final boolean mIsDisplayResolutionRangeVotingEnabled;
- private final boolean mVsyncProximityVoteEnabled;
+ private final boolean mSupportedModesVoteEnabled;
private final boolean mSupportsFrameRateOverride;
private final boolean mLoggingEnabled;
- VoteSummary(boolean isDisplayResolutionRangeVotingEnabled, boolean vsyncProximityVoteEnabled,
+ VoteSummary(boolean isDisplayResolutionRangeVotingEnabled, boolean supportedModesVoteEnabled,
boolean loggingEnabled, boolean supportsFrameRateOverride) {
mIsDisplayResolutionRangeVotingEnabled = isDisplayResolutionRangeVotingEnabled;
- mVsyncProximityVoteEnabled = vsyncProximityVoteEnabled;
+ mSupportedModesVoteEnabled = supportedModesVoteEnabled;
mLoggingEnabled = loggingEnabled;
mSupportsFrameRateOverride = supportsFrameRateOverride;
reset();
@@ -253,7 +253,7 @@ final class VoteSummary {
}
private boolean validateModeSupported(Display.Mode mode) {
- if (supportedModes == null || !mVsyncProximityVoteEnabled) {
+ if (supportedModes == null || !mSupportedModesVoteEnabled) {
return true;
}
for (SupportedModesVote.SupportedMode supportedMode : supportedModes) {
@@ -298,7 +298,7 @@ final class VoteSummary {
return false;
}
- if (supportedModes != null && mVsyncProximityVoteEnabled && supportedModes.isEmpty()) {
+ if (supportedModes != null && mSupportedModesVoteEnabled && supportedModes.isEmpty()) {
if (mLoggingEnabled) {
Slog.w(TAG, "Vote summary resulted in empty set (empty supportedModes)");
}
@@ -370,7 +370,7 @@ final class VoteSummary {
+ ", supportedModes=" + supportedModes
+ ", mIsDisplayResolutionRangeVotingEnabled="
+ mIsDisplayResolutionRangeVotingEnabled
- + ", mVsyncProximityVoteEnabled=" + mVsyncProximityVoteEnabled
+ + ", mSupportedModesVoteEnabled=" + mSupportedModesVoteEnabled
+ ", mSupportsFrameRateOverride=" + mSupportsFrameRateOverride + " }";
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c440a6461de2..16e043cfb64d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -6499,10 +6499,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
nextEnabledImes).getId();
// Reset enabled IMEs.
- settings.putEnabledInputMethodsStr("");
- nextEnabledImes.forEach(
- imi -> settings.appendAndPutEnabledInputMethodLocked(
- imi.getId()));
+ final String[] nextEnabledImeIds = new String[nextEnabledImes.size()];
+ for (int i = 0; i < nextEnabledImeIds.length; ++i) {
+ nextEnabledImeIds[i] = nextEnabledImes.get(i).getId();
+ }
+ settings.putEnabledInputMethodsStr(InputMethodUtils.concatEnabledImeIds(
+ settings.getEnabledInputMethodsStr(), nextEnabledImeIds));
// Reset selected IME.
settings.putSelectedInputMethod(nextIme);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 2128356e69c6..773293f83323 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -33,6 +33,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.IntArray;
import android.util.Pair;
import android.util.Printer;
@@ -50,6 +51,8 @@ import com.android.server.textservices.TextServicesManagerInternal;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.StringJoiner;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -952,24 +955,64 @@ final class InputMethodUtils {
final String enabledInputMethodsStr = TextUtils.nullIfEmpty(
SecureSettingsWrapper.getString(Settings.Secure.ENABLED_INPUT_METHODS, null,
userId));
- if (enabledInputMethodsStr == null) {
- return List.of();
+ final ArrayList<String> result = new ArrayList<>();
+ splitEnabledImeStr(enabledInputMethodsStr, result::add);
+ return result;
+ }
+
+ /**
+ * Split enabled IME string ({@link Settings.Secure#ENABLED_INPUT_METHODS}) into IME IDs.
+ *
+ * @param text a text formatted with {@link Settings.Secure#ENABLED_INPUT_METHODS}.
+ * @param consumer {@link Consumer} called back when a new IME ID is found.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ static void splitEnabledImeStr(@Nullable String text, @NonNull Consumer<String> consumer) {
+ if (TextUtils.isEmpty(text)) {
+ return;
}
final TextUtils.SimpleStringSplitter inputMethodSplitter =
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATOR);
final TextUtils.SimpleStringSplitter subtypeSplitter =
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR);
- inputMethodSplitter.setString(enabledInputMethodsStr);
- final ArrayList<String> result = new ArrayList<>();
+ inputMethodSplitter.setString(text);
while (inputMethodSplitter.hasNext()) {
String nextImsStr = inputMethodSplitter.next();
subtypeSplitter.setString(nextImsStr);
if (subtypeSplitter.hasNext()) {
// The first element is ime id.
- result.add(subtypeSplitter.next());
+ consumer.accept(subtypeSplitter.next());
}
}
- return result;
+ }
+
+ /**
+ * Concat given IME IDs with an existing enabled IME
+ * ({@link Settings.Secure#ENABLED_INPUT_METHODS}).
+ *
+ * @param existingEnabledImeId an existing {@link Settings.Secure#ENABLED_INPUT_METHODS} to
+ * which {@code imeIDs} will be added.
+ * @param imeIds an array of IME IDs to be added. For IME IDs that are already seen in
+ * {@code existingEnabledImeId} will be skipped.
+ * @return a new enabled IME ID string that can be stored in
+ * {@link Settings.Secure#ENABLED_INPUT_METHODS}.
+ */
+ @NonNull
+ static String concatEnabledImeIds(@NonNull String existingEnabledImeId,
+ @NonNull String... imeIds) {
+ final ArraySet<String> alreadyEnabledIds = new ArraySet<>();
+ final StringJoiner joiner = new StringJoiner(Character.toString(INPUT_METHOD_SEPARATOR));
+ if (!TextUtils.isEmpty(existingEnabledImeId)) {
+ splitEnabledImeStr(existingEnabledImeId, alreadyEnabledIds::add);
+ joiner.add(existingEnabledImeId);
+ }
+ for (String id : imeIds) {
+ if (!alreadyEnabledIds.contains(id)) {
+ joiner.add(id);
+ alreadyEnabledIds.add(id);
+ }
+ }
+ return joiner.toString();
}
/**
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index df9e7417054b..5e18727459c6 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -964,6 +964,7 @@ class MediaRouter2ServiceImpl {
disposeUserIfNeededLocked(userRecord); // since router removed from user
}
+ @GuardedBy("mLock")
private void setDiscoveryRequestWithRouter2Locked(@NonNull RouterRecord routerRecord,
@NonNull RouteDiscoveryPreference discoveryRequest) {
if (routerRecord.mDiscoveryPreference.equals(discoveryRequest)) {
@@ -1016,6 +1017,7 @@ class MediaRouter2ServiceImpl {
routeListingPreference));
}
+ @GuardedBy("mLock")
private void setRouteVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull MediaRoute2Info route, int volume) {
final IBinder binder = router.asBinder();
@@ -1035,6 +1037,7 @@ class MediaRouter2ServiceImpl {
}
}
+ @GuardedBy("mLock")
private void requestCreateSessionWithRouter2Locked(int requestId, long managerRequestId,
@NonNull IMediaRouter2 router, @NonNull RoutingSessionInfo oldSession,
@NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
@@ -1117,6 +1120,7 @@ class MediaRouter2ServiceImpl {
sessionHints));
}
+ @GuardedBy("mLock")
private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
@@ -1138,6 +1142,7 @@ class MediaRouter2ServiceImpl {
DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void deselectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
@@ -1159,6 +1164,7 @@ class MediaRouter2ServiceImpl {
DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void transferToRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
@@ -1191,6 +1197,7 @@ class MediaRouter2ServiceImpl {
}
}
+ @GuardedBy("mLock")
private void setSessionVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, int volume) {
final IBinder binder = router.asBinder();
@@ -1215,6 +1222,7 @@ class MediaRouter2ServiceImpl {
DUMMY_REQUEST_ID, uniqueSessionId, volume));
}
+ @GuardedBy("mLock")
private void releaseSessionWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId) {
final IBinder binder = router.asBinder();
@@ -1240,6 +1248,7 @@ class MediaRouter2ServiceImpl {
// Start of locked methods that are used by MediaRouter2Manager.
+ @GuardedBy("mLock")
private List<RoutingSessionInfo> getRemoteSessionsLocked(
@NonNull IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
@@ -1330,6 +1339,7 @@ class MediaRouter2ServiceImpl {
UserHandler::notifyInitialRoutesToManager, userRecord.mHandler, manager));
}
+ @GuardedBy("mLock")
private void unregisterManagerLocked(@NonNull IMediaRouter2Manager manager, boolean died) {
ManagerRecord managerRecord = mAllManagerRecords.remove(manager.asBinder());
if (managerRecord == null) {
@@ -1355,6 +1365,7 @@ class MediaRouter2ServiceImpl {
disposeUserIfNeededLocked(userRecord); // since manager removed from user
}
+ @GuardedBy("mLock")
private void startScanLocked(@NonNull IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1368,6 +1379,7 @@ class MediaRouter2ServiceImpl {
managerRecord.startScan();
}
+ @GuardedBy("mLock")
private void stopScanLocked(@NonNull IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1381,6 +1393,7 @@ class MediaRouter2ServiceImpl {
managerRecord.stopScan();
}
+ @GuardedBy("mLock")
private void setRouteVolumeWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull MediaRoute2Info route, int volume) {
@@ -1402,6 +1415,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, route, volume));
}
+ @GuardedBy("mLock")
private void requestCreateSessionWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager, @NonNull RoutingSessionInfo oldSession,
@NonNull MediaRoute2Info route) {
@@ -1455,6 +1469,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, routerRecord, managerRecord, oldSession, route));
}
+ @GuardedBy("mLock")
private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = manager.asBinder();
@@ -1479,6 +1494,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void deselectRouteWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
@@ -1504,6 +1520,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void transferToRouteWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
@@ -1529,6 +1546,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void setSessionVolumeWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, int volume) {
@@ -1550,6 +1568,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, uniqueSessionId, volume));
}
+ @GuardedBy("mLock")
private void releaseSessionWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager, @NonNull String uniqueSessionId) {
final IBinder binder = manager.asBinder();
@@ -1652,6 +1671,7 @@ class MediaRouter2ServiceImpl {
// TODO: This assumes that only one router exists in a package.
// Do this in Android S or later.
+ @GuardedBy("mLock")
RouterRecord findRouterRecordLocked(String packageName) {
for (RouterRecord routerRecord : mRouterRecords) {
if (TextUtils.equals(routerRecord.mPackageName, packageName)) {
@@ -1739,6 +1759,7 @@ class MediaRouter2ServiceImpl {
return mHasModifyAudioRoutingPermission || mHasBluetoothRoutingPermission.get();
}
+ @GuardedBy("mLock")
public void maybeUpdateSystemRoutingPermissionLocked() {
boolean oldSystemRoutingPermissionValue = hasSystemRoutingPermission();
mHasBluetoothRoutingPermission.set(checkCallerHasBluetoothPermissions(mPid, mUid));
@@ -2063,6 +2084,7 @@ class MediaRouter2ServiceImpl {
this, provider, uniqueRequestId, reason));
}
+ @GuardedBy("mLock")
@Nullable
public RouterRecord findRouterWithSessionLocked(@NonNull String uniqueSessionId) {
return mSessionToRouterMap.get(uniqueSessionId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index b12180bffdcd..4b8de4e8c6f1 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -19,6 +19,7 @@ package com.android.server.notification;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
+import android.service.notification.DeviceEffectsApplier;
import java.util.Set;
@@ -54,4 +55,22 @@ public interface NotificationManagerInternal {
void cleanupHistoryFiles();
void removeBitmaps();
+
+ /**
+ * Sets the {@link DeviceEffectsApplier} that will be used to apply the different
+ * {@link android.service.notification.ZenDeviceEffects} that are relevant for the platform
+ * when {@link android.service.notification.ZenModeConfig.ZenRule} instances are activated and
+ * deactivated.
+ *
+ * <p>This method is optional and needs only be called if the platform supports non-standard
+ * effects (i.e. any that are not <em>public APIs</em> in
+ * {@link android.service.notification.ZenDeviceEffects}, or if they must be applied in a
+ * non-standard fashion. If not used, a {@link DefaultDeviceEffectsApplier} will be invoked,
+ * which should be sufficient for most devices.
+ *
+ * <p>If this method is called, it <em>must</em> be during system startup and <em>before</em>
+ * the {@link com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START} boot phase.
+ * Otherwise an {@link IllegalStateException} will be thrown.
+ */
+ void setDeviceEffectsApplier(DeviceEffectsApplier applier);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 66a974080a43..e7ae61072db4 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -251,6 +251,7 @@ import android.provider.Settings.Secure;
import android.service.notification.Adjustment;
import android.service.notification.Condition;
import android.service.notification.ConversationChannelWrapper;
+import android.service.notification.DeviceEffectsApplier;
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
import android.service.notification.IStatusBarNotificationHolder;
@@ -6964,6 +6965,18 @@ public class NotificationManagerService extends SystemService {
}
}
}
+
+ @Override
+ public void setDeviceEffectsApplier(DeviceEffectsApplier applier) {
+ if (!android.app.Flags.modesApi()) {
+ return;
+ }
+ if (mZenModeHelper == null) {
+ throw new IllegalStateException("ZenModeHelper is not yet ready!");
+ }
+ // This can also throw IllegalStateException if called too late.
+ mZenModeHelper.setDeviceEffectsApplier(applier);
+ }
};
private static boolean isBigPictureWithBitmapOrIcon(Notification n) {
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 7b35589ae682..7f58e75e0287 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -837,13 +837,11 @@ public final class BroadcastHelper {
}
final String removedPackage = packageRemovedInfo.mRemovedPackage;
- final int removedAppId = packageRemovedInfo.mRemovedAppId;
- final int uid = packageRemovedInfo.mUid;
final String installerPackageName = packageRemovedInfo.mInstallerPackageName;
final SparseArray<int[]> broadcastAllowList = packageRemovedInfo.mBroadcastAllowList;
Bundle extras = new Bundle(2);
- extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
+ extras.putInt(Intent.EXTRA_UID, packageRemovedInfo.mUid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
sendPackageBroadcastAndNotify(Intent.ACTION_PACKAGE_ADDED, removedPackage, extras,
0, null /*targetPackage*/, null, null, null, broadcastAllowList, null);
@@ -888,8 +886,6 @@ public final class BroadcastHelper {
boolean removedBySystem,
boolean isArchived) {
final String removedPackage = packageRemovedInfo.mRemovedPackage;
- final int removedAppId = packageRemovedInfo.mRemovedAppId;
- final int uid = packageRemovedInfo.mUid;
final String installerPackageName = packageRemovedInfo.mInstallerPackageName;
final int[] broadcastUserIds = packageRemovedInfo.mBroadcastUsers;
final int[] instantUserIds = packageRemovedInfo.mInstantUserIds;
@@ -902,8 +898,7 @@ public final class BroadcastHelper {
final boolean isStaticSharedLib = packageRemovedInfo.mIsStaticSharedLib;
Bundle extras = new Bundle();
- final int removedUid = removedAppId >= 0 ? removedAppId : uid;
- extras.putInt(Intent.EXTRA_UID, removedUid);
+ extras.putInt(Intent.EXTRA_UID, packageRemovedInfo.mUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
extras.putBoolean(Intent.EXTRA_SYSTEM_UPDATE_UNINSTALL, isRemovedPackageSystemUpdate);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
@@ -940,10 +935,10 @@ public final class BroadcastHelper {
sendPackageBroadcastAndNotify(Intent.ACTION_PACKAGE_FULLY_REMOVED,
removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
null, broadcastUserIds, instantUserIds, broadcastAllowList, null);
- packageSender.notifyPackageRemoved(removedPackage, removedUid);
+ packageSender.notifyPackageRemoved(removedPackage, packageRemovedInfo.mUid);
}
}
- if (removedAppId >= 0) {
+ if (packageRemovedInfo.mIsAppIdRemoved) {
// If a system app's updates are uninstalled the UID is not actually removed. Some
// services need to know the package name affected.
if (isReplace) {
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 27f4e11c53ad..482807c397ea 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -518,7 +518,9 @@ public interface Computer extends PackageDataSnapshot {
boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId)
throws PackageManager.NameNotFoundException;
- boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId);
+ /** Check if the package is suspending any package. */
+ boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
+ @UserIdInt int suspendingUserId, int targetUserId);
@NonNull
ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index abfd5715810e..3cb2420cd223 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -96,6 +96,7 @@ import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.pm.VersionedPackage;
import android.os.Binder;
import android.os.Build;
@@ -3864,19 +3865,15 @@ public class ComputerEngine implements Computer {
} finally {
Binder.restoreCallingIdentity(identity);
}
-
- var usingSharedLibraryPair =
- getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(),
libInfo.getPackageName(), libInfo.getAllCodePaths(),
libInfo.getName(), libInfo.getLongVersion(),
libInfo.getType(), declaringPackage,
- usingSharedLibraryPair.first,
(libInfo.getDependencies() == null
? null
: new ArrayList<>(libInfo.getDependencies())),
- libInfo.isNative());
-
+ libInfo.isNative(),
+ getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId));
if (result == null) {
result = new ArrayList<>();
}
@@ -5012,11 +5009,13 @@ public class ComputerEngine implements Computer {
@Override
public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
- @UserIdInt int userId) {
+ @UserIdInt int suspendingUserId, int targetUserId) {
+ final UserPackage suspender = UserPackage.of(suspendingUserId, suspendingPackage);
for (final PackageStateInternal packageState : getPackageStates().values()) {
- final PackageUserStateInternal state = packageState.getUserStateOrDefault(userId);
+ final PackageUserStateInternal state =
+ packageState.getUserStateOrDefault(targetUserId);
if (state.getSuspendParams() != null
- && state.getSuspendParams().containsKey(suspendingPackage)) {
+ && state.getSuspendParams().containsKey(suspender)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index dcf921c90885..aa7f0d3c668a 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -510,7 +510,10 @@ final class DeletePackageHelper {
}
if (clearPackageStateAndReturn) {
mRemovePackageHelper.clearPackageStateForUserLIF(ps, userId, flags);
- outInfo.mRemovedAppId = ps.getAppId();
+ // Legacy behavior to report appId as UID here.
+ // The final broadcasts will contain a per-user UID.
+ outInfo.mUid = ps.getAppId();
+ outInfo.mIsAppIdRemoved = true;
mPm.scheduleWritePackageRestrictions(user);
return;
}
@@ -555,6 +558,7 @@ final class DeletePackageHelper {
boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles,
@NonNull PackageRemovedInfo outInfo, boolean writeSettings) {
synchronized (mPm.mLock) {
+ // Since the package is being deleted in all users, report appId as the uid
outInfo.mUid = ps.getAppId();
outInfo.mBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
mPm.snapshotComputer(), ps, allUserHandles,
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 6480d6483062..0fa7aa5473b2 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -2912,7 +2912,8 @@ final class InstallPackageHelper {
info.mInstallerPackageName = request.getInstallerPackageName();
info.mRemovedUsers = firstUserIds;
info.mBroadcastUsers = firstUserIds;
- info.mRemovedAppId = request.getAppId();
+ info.mUid = request.getAppId();
+ info.mIsAppIdRemoved = true;
info.mRemovedPackageVersionCode = request.getPkg().getLongVersionCode();
info.mRemovedForAllUsers = true;
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 9a51cc0e26ba..ee780d99b6b6 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -818,7 +818,8 @@ final class InstallRequest {
public void setRemovedAppId(int appId) {
if (mRemovedInfo != null) {
- mRemovedInfo.mRemovedAppId = appId;
+ mRemovedInfo.mUid = appId;
+ mRemovedInfo.mIsAppIdRemoved = true;
}
}
diff --git a/services/core/java/com/android/server/pm/KnownPackages.java b/services/core/java/com/android/server/pm/KnownPackages.java
index 154709a62095..83831ca61aa1 100644
--- a/services/core/java/com/android/server/pm/KnownPackages.java
+++ b/services/core/java/com/android/server/pm/KnownPackages.java
@@ -77,6 +77,8 @@ public final class KnownPackages {
// Please note the numbers should be continuous.
public static final int LAST_KNOWN_PACKAGE = PACKAGE_WEARABLE_SENSING;
+ static final String SYSTEM_PACKAGE_NAME = "android";
+
private final DefaultAppProvider mDefaultAppProvider;
private final String mRequiredInstallerPackage;
private final String mRequiredUninstallerPackage;
@@ -186,7 +188,7 @@ public final class KnownPackages {
case PACKAGE_SETUP_WIZARD:
return snapshot.filterOnlySystemPackages(mSetupWizardPackage);
case PACKAGE_SYSTEM:
- return new String[]{"android"};
+ return new String[]{SYSTEM_PACKAGE_NAME};
case PACKAGE_VERIFIER:
return snapshot.filterOnlySystemPackages(mRequiredVerifierPackages);
case PACKAGE_SYSTEM_TEXT_CLASSIFIER:
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index ba66377beb8a..127bf495d2ac 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -822,7 +822,7 @@ public class LauncherAppsService extends SystemService {
return new LauncherActivityInfoInternal(
activityInfo,
new IncrementalStatesInfo(
- false /* isLoading */, 1 /* progress */, 0 /* loadingCompletedTime */),
+ false /* isLoading */, 0 /* progress */, 0 /* loadingCompletedTime */),
user);
}
@@ -1599,6 +1599,33 @@ public class LauncherAppsService extends SystemService {
}
@Override
+ public @Nullable IntentSender getAppMarketActivityIntent(@NonNull String callingPackage,
+ @Nullable String packageName, @NonNull UserHandle user) {
+ // Only system launchers, which have access to recents should have access to this API.
+ // TODO(b/303803157): Update access control for this API to default Launcher app.
+ if (!mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid())) {
+ throw new SecurityException("Caller is not the recents app");
+ }
+ if (!canAccessProfile(user.getIdentifier(),
+ "Can't access AppMarketActivity for another user")) {
+ return null;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ // TODO(b/316118005): Add code to launch the app installer for the packageName.
+ Intent appMarketIntent = new Intent(Intent.ACTION_MAIN);
+ appMarketIntent.addCategory(Intent.CATEGORY_APP_MARKET);
+ final PendingIntent pi = PendingIntent.getActivityAsUser(
+ mContext, /* requestCode */ 0, appMarketIntent, PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
+ /* options */ null, user);
+ return pi == null ? null : pi.getIntentSender();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void startActivityAsUser(IApplicationThread caller, String callingPackage,
String callingFeatureId, ComponentName component, Rect sourceBounds,
Bundle opts, UserHandle user) throws RemoteException {
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index 6b05edf7c25a..2864a8b42445 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -165,7 +165,7 @@ public class PackageArchiver {
Computer snapshot = mPm.snapshotComputer();
int userId = userHandle.getIdentifier();
int binderUid = Binder.getCallingUid();
- if (!PackageManagerServiceUtils.isRootOrShell(binderUid)) {
+ if (!PackageManagerServiceUtils.isSystemOrRootOrShell(binderUid)) {
verifyCaller(snapshot.getPackageUid(callerPackageName, 0, userId), binderUid);
}
snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 7d6dd62153c1..2942bbb86e62 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -821,6 +821,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
params.installFlags &= ~PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK;
}
+ params.installFlags &= ~PackageManager.INSTALL_UNARCHIVE;
+ if (Flags.archiving() && params.appPackageName != null) {
+ PackageStateInternal ps = mPm.snapshotComputer().getPackageStateInternal(
+ params.appPackageName, SYSTEM_UID);
+ if (ps != null
+ && PackageArchiver.isArchived(ps.getUserStateOrDefault(userId))
+ && PackageArchiver.getResponsibleInstallerPackage(ps)
+ .equals(requestedInstallerPackageName)) {
+ params.installFlags |= PackageManager.INSTALL_UNARCHIVE;
+ }
+ }
+
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
&& !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)
&& (snapshot.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM)
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index c737b45ae885..8da168375447 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -19,6 +19,8 @@ package com.android.server.pm;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -37,6 +39,7 @@ import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -250,7 +253,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
getSuspendPackageHelper().removeSuspensionsBySuspendingPackage(snapshot(),
new String[]{packageName},
(suspendingPackage) -> !PackageManagerService.PLATFORM_PACKAGE_NAME.equals(
- suspendingPackage),
+ suspendingPackage.packageName),
userId);
}
@@ -269,7 +272,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
- public final String getSuspendingPackage(String suspendedPackage, int userId) {
+ public final UserPackage getSuspendingPackage(String suspendedPackage, int userId) {
return getSuspendPackageHelper().getSuspendingPackage(snapshot(), suspendedPackage, userId,
Binder.getCallingUid());
}
@@ -277,7 +280,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
public final SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
- String suspendingPackage, int userId) {
+ UserPackage suspendingPackage, int userId) {
return getSuspendPackageHelper().getSuspendedDialogInfo(snapshot(), suspendedPackage,
suspendingPackage, userId, Binder.getCallingUid());
}
@@ -683,14 +686,16 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
- public final void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
- mService.unsuspendForSuspendingPackage(snapshot(), packageName, affectedUser);
+ public final void unsuspendAdminSuspendedPackages(int affectedUser) {
+ final int suspendingUserId = affectedUser;
+ mService.unsuspendForSuspendingPackage(snapshot(), PLATFORM_PACKAGE_NAME, suspendingUserId);
}
@Override
@Deprecated
- public final boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
- return snapshot().isSuspendingAnyPackages(suspendingPackage, userId);
+ public final boolean isAdminSuspendingAnyPackages(int userId) {
+ final int suspendingUserId = userId;
+ return snapshot().isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, suspendingUserId, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 56365b676618..bc441b84c58b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -292,6 +292,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* Keep track of all those APKs everywhere.
@@ -3137,7 +3138,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
private void enforceCanSetPackagesSuspendedAsUser(@NonNull Computer snapshot,
- boolean quarantined, String callingPackage, int callingUid, int userId,
+ boolean quarantined, UserPackage suspender, int callingUid, int targetUserId,
String callingMethod) {
if (callingUid == Process.ROOT_UID
// Need to compare app-id to allow system dialogs access on secondary users
@@ -3145,9 +3146,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
return;
}
- final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
+ final String ownerPackage =
+ mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(targetUserId);
if (ownerPackage != null) {
- final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, userId);
+ final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, targetUserId);
if (ownerUid == callingUid) {
return;
}
@@ -3168,25 +3170,27 @@ public class PackageManagerService implements PackageSender, TestUtilityService
callingMethod);
}
- final int packageUid = snapshot.getPackageUid(callingPackage, 0, userId);
+ final int packageUid = snapshot.getPackageUid(suspender.packageName, 0, targetUserId);
final boolean allowedPackageUid = packageUid == callingUid;
// TODO(b/139383163): remove special casing for shell and enforce INTERACT_ACROSS_USERS_FULL
final boolean allowedShell = callingUid == SHELL_UID
&& UserHandle.isSameApp(packageUid, callingUid);
if (!allowedShell && !allowedPackageUid) {
- throw new SecurityException("Calling package " + callingPackage + " in user "
- + userId + " does not belong to calling uid " + callingUid);
+ throw new SecurityException("Suspending package " + suspender.packageName
+ + " in user " + targetUserId + " does not belong to calling uid " + callingUid);
}
}
void unsuspendForSuspendingPackage(@NonNull Computer computer, String suspendingPackage,
- @UserIdInt int userId) {
+ @UserIdInt int suspendingUserId) {
// TODO: This can be replaced by a special parameter to iterate all packages, rather than
// this weird pre-collect of all packages.
final String[] allPackages = computer.getPackageStates().keySet().toArray(new String[0]);
+ final Predicate<UserPackage> suspenderPredicate =
+ UserPackage.of(suspendingUserId, suspendingPackage)::equals;
mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer,
- allPackages, suspendingPackage::equals, userId);
+ allPackages, suspenderPredicate, suspendingUserId);
}
void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
@@ -5259,8 +5263,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
if (!snapshot.isPackageSuspendedForUser(packageName, userId)) {
return null;
}
- return mSuspendPackageHelper.getSuspendingPackage(snapshot, packageName, userId,
- callingUid);
+ final UserPackage suspender = mSuspendPackageHelper.getSuspendingPackage(
+ snapshot, packageName, userId, callingUid);
+ return suspender != null ? suspender.packageName : null;
} catch (PackageManager.NameNotFoundException e) {
return null;
}
@@ -6198,7 +6203,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
PersistableBundle appExtras, PersistableBundle launcherExtras,
- SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId) {
+ SuspendDialogInfo dialogInfo, int flags, String suspendingPackage,
+ int suspendingUserId, int targetUserId) {
final int callingUid = Binder.getCallingUid();
boolean quarantined = false;
if (Flags.quarantinedEnabled()) {
@@ -6207,14 +6213,15 @@ public class PackageManagerService implements PackageSender, TestUtilityService
} else if (FeatureFlagUtils.isEnabled(mContext,
SETTINGS_TREAT_PAUSE_AS_QUARANTINE)) {
final String wellbeingPkg = mContext.getString(R.string.config_systemWellbeing);
- quarantined = callingPackage.equals(wellbeingPkg);
+ quarantined = suspendingPackage.equals(wellbeingPkg);
}
}
final Computer snapshot = snapshotComputer();
- enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, callingPackage, callingUid,
- userId, "setPackagesSuspendedAsUser");
+ final UserPackage suspender = UserPackage.of(targetUserId, suspendingPackage);
+ enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, suspender, callingUid,
+ targetUserId, "setPackagesSuspendedAsUser");
return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended,
- appExtras, launcherExtras, dialogInfo, callingPackage, userId, callingUid,
+ appExtras, launcherExtras, dialogInfo, suspender, targetUserId, callingUid,
quarantined);
}
@@ -6653,7 +6660,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final Computer computer = snapshotComputer();
final String[] allPackages = computer.getAllAvailablePackageNames();
mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages,
- (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
+ (suspender) -> !PLATFORM_PACKAGE_NAME.equals(suspender.packageName),
userId);
}
@@ -6667,8 +6674,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String[] setPackagesSuspendedByAdmin(
@UserIdInt int userId, @NonNull String[] packageNames, boolean suspended) {
- return mSuspendPackageHelper.setPackagesSuspendedByAdmin(
- snapshotComputer(), userId, packageNames, suspended);
+ final int suspendingUserId = userId;
+ final UserPackage suspender = UserPackage.of(
+ suspendingUserId, PackageManagerService.PLATFORM_PACKAGE_NAME);
+ return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames,
+ suspended, null /* appExtras */, null /* launcherExtras */,
+ null /* dialogInfo */, suspender, userId, Process.SYSTEM_UID,
+ false /* quarantined */);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 215e9528a35e..243fb16b19ae 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2827,7 +2827,7 @@ class PackageManagerShellCommand extends ShellCommand {
mInterface.setPackagesSuspendedAsUser(packageNames.toArray(new String[] {}),
suspendedState, ((appExtras.size() > 0) ? appExtras : null),
((launcherExtras.size() > 0) ? launcherExtras : null),
- info, flags, callingPackage, translatedUserId);
+ info, flags, callingPackage, UserHandle.USER_SYSTEM, translatedUserId);
for (int i = 0; i < packageNames.size(); i++) {
final String packageName = packageNames.get(i);
pw.println("Package " + packageName + " new suspended state: "
@@ -2872,16 +2872,16 @@ class PackageManagerShellCommand extends ShellCommand {
UserHandle.USER_NULL, "runGrantRevokePermission"));
List<PackageInfo> packageInfos;
+ PackageManager pm = mContext.createContextAsUser(translatedUser, 0).getPackageManager();
if (pkg == null) {
- packageInfos = mContext.getPackageManager().getInstalledPackages(
- PackageManager.GET_PERMISSIONS);
+ packageInfos = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
} else {
try {
- packageInfos = Collections.singletonList(
- mContext.getPackageManager().getPackageInfo(pkg,
- PackageManager.GET_PERMISSIONS));
+ packageInfos = Collections.singletonList(pm.getPackageInfo(pkg,
+ PackageManager.GET_PERMISSIONS));
} catch (NameNotFoundException e) {
getErrPrintWriter().println("Error: package not found");
+ getOutPrintWriter().println("Failure [package not found]");
return 1;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
index 7ee1772adead..881b0b398f9a 100644
--- a/services/core/java/com/android/server/pm/PackageRemovedInfo.java
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -25,7 +25,7 @@ final class PackageRemovedInfo {
String mRemovedPackage;
String mInstallerPackageName;
int mUid = -1;
- int mRemovedAppId = -1;
+ boolean mIsAppIdRemoved = false;
int[] mOrigUsers;
int[] mRemovedUsers = null;
int[] mBroadcastUsers = null;
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 7d0a1f6afe1d..28a90f3d6ab6 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -32,6 +32,7 @@ import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
@@ -952,7 +953,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
void setUserState(int userId, long ceDataInode, long deDataInode, int enabled,
boolean installed, boolean stopped, boolean notLaunched, boolean hidden,
- int distractionFlags, ArrayMap<String, SuspendParams> suspendParams,
+ int distractionFlags, ArrayMap<UserPackage, SuspendParams> suspendParams,
boolean instantApp, boolean virtualPreload, String lastDisableAppCaller,
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
int installReason, int uninstallReason,
@@ -1182,7 +1183,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
if (state.isSuspended()) {
for (int j = 0; j < state.getSuspendParams().size(); j++) {
proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE,
- state.getSuspendParams().keyAt(j));
+ state.getSuspendParams().keyAt(j).packageName);
}
}
proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.isStopped());
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 981f24bc179a..b6de0e5c030f 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -20,15 +20,19 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIB
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_APEX;
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
+import static com.android.server.pm.PackageManagerService.TAG;
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
+import android.os.Build;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
@@ -49,6 +53,8 @@ import java.util.Map;
* as install) led to the request.
*/
final class ReconcilePackageUtils {
+ private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE || true;
+
public static List<ReconciledPackage> reconcilePackages(
List<InstallRequest> installRequests,
Map<String, AndroidPackage> allPackages,
@@ -90,6 +96,8 @@ final class ReconcilePackageUtils {
}
}
+ final AndroidPackage systemPackage = allPackages.get(KnownPackages.SYSTEM_PACKAGE_NAME);
+
for (InstallRequest installRequest : installRequests) {
final String installPackageName = installRequest.getParsedPackage().getPackageName();
final List<SharedLibraryInfo> allowedSharedLibInfos =
@@ -133,6 +141,9 @@ final class ReconcilePackageUtils {
if (parsedPackage != null) {
signingDetails = parsedPackage.getSigningDetails();
}
+ final boolean isSystemPackage =
+ ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0);
+ final boolean isApex = (scanFlags & SCAN_AS_APEX) != 0;
SharedUserSetting sharedUserSetting = settings.getSharedUserSettingLPr(
signatureCheckPs);
if (ksms.shouldCheckUpgradeKeySetLocked(
@@ -141,7 +152,7 @@ final class ReconcilePackageUtils {
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
} else {
- if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) {
+ if (!isSystemPackage) {
throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + parsedPackage.getPackageName()
+ " upgrade keys do not match the previously installed"
@@ -168,9 +179,23 @@ final class ReconcilePackageUtils {
removeAppKeySetData = true;
}
+ if (!isSystemPackage && !isApex && signingDetails != null
+ && systemPackage != null && systemPackage.getSigningDetails() != null
+ && systemPackage.getSigningDetails().checkCapability(
+ signingDetails,
+ SigningDetails.CertCapabilities.PERMISSION)) {
+ Slog.d(TAG, "Non-preload app associated with system signature: "
+ + signatureCheckPs.getPackageName());
+ if (!ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE) {
+ throw new ReconcileFailure(
+ INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ "Non-preload app associated with system signature: "
+ + signatureCheckPs.getPackageName());
+ }
+ }
+
// if this is is a sharedUser, check to see if the new package is signed by a
- // newer
- // signing certificate than the existing one, and if so, copy over the new
+ // newer signing certificate than the existing one, and if so, copy over the new
// details
if (sharedUserSetting != null) {
// Attempt to merge the existing lineage for the shared SigningDetails with
@@ -203,7 +228,7 @@ final class ReconcilePackageUtils {
}
}
} catch (PackageManagerException e) {
- if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) {
+ if (!isSystemPackage) {
throw new ReconcileFailure(e);
}
signingDetails = parsedPackage.getSigningDetails();
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 8ff4a6dd9440..f42b43f5aeef 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -252,40 +252,103 @@ final class RemovePackageHelper {
}
}
+ /**
+ * This method clears the data and states stored in the system that are related to the
+ * package being deleted and the target user, including the data directory.
+ * If the DELETE_KEEP_DATA flag is set, everything is preserved except ART profiles.
+ * Make sure this flag is set for partially installed apps. If not it's meaningless to
+ * delete a partially installed application.
+ */
public void clearPackageStateForUserLIF(PackageSetting ps, int userId, int flags) {
+ final String packageName = ps.getPackageName();
+ // Step 1: always destroy app profiles.
+ mAppDataHelper.destroyAppProfilesLIF(packageName);
+
+ // Everything else is preserved if the DELETE_KEEP_DATA flag is on
+ if ((flags & PackageManager.DELETE_KEEP_DATA) != 0) {
+ return;
+ }
+
final AndroidPackage pkg;
final SharedUserSetting sus;
synchronized (mPm.mLock) {
- pkg = mPm.mPackages.get(ps.getPackageName());
+ pkg = mPm.mPackages.get(packageName);
sus = mPm.mSettings.getSharedUserSettingLPr(ps);
}
- mAppDataHelper.destroyAppProfilesLIF(ps.getPackageName());
+ final AndroidPackage resolvedPkg;
+ if (pkg != null) {
+ resolvedPkg = pkg;
+ } else {
+ // We don't have a parsed package when it lives on an ejected
+ // adopted storage device, so fake something together
+ resolvedPkg = PackageImpl.buildFakeForDeletion(packageName, ps.getVolumeUuid());
+ }
+
+ // Step 2: destroy app data.
+ mAppDataHelper.destroyAppDataLIF(resolvedPkg, userId,
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+ if (userId != UserHandle.USER_ALL) {
+ ps.setCeDataInode(-1, userId);
+ ps.setDeDataInode(-1, userId);
+ }
- final List<AndroidPackage> sharedUserPkgs =
- sus != null ? sus.getPackages() : Collections.emptyList();
final PreferredActivityHelper preferredActivityHelper = new PreferredActivityHelper(mPm,
mBroadcastHelper);
- final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManagerInternal.getUserIds()
- : new int[] {userId};
- for (int nextUserId : userIds) {
+ if (userId == UserHandle.USER_ALL) {
if (DEBUG_REMOVE) {
- Slog.d(TAG, "Updating package:" + ps.getPackageName() + " install state for user:"
- + nextUserId);
+ Slog.d(TAG, "Clear package:" + packageName + " state for all users");
}
- if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
- mAppDataHelper.destroyAppDataLIF(pkg, nextUserId,
- FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
- ps.setCeDataInode(-1, nextUserId);
- ps.setDeDataInode(-1, nextUserId);
+ // Step 3: inform DomainVerificationManager.
+ mPm.mDomainVerificationManager.clearPackage(packageName);
+ synchronized (mPm.mLock) {
+ // Step 3.1 (only for USER_ALL): notify KeySetManagerService.
+ mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
+ // Step 3.2 (only for USER_ALL): update installer ownership.
+ mPm.mInjector.getUpdateOwnershipHelper().removeUpdateOwnerDenyList(packageName);
+ // Step 3.3 (only for USER_ALL): update AppsFilter.
+ final Computer snapshot = mPm.snapshotComputer();
+ mPm.mAppsFilter.removePackage(snapshot,
+ snapshot.getPackageStateInternal(packageName));
+ // Step 4: clear perferred activities.
+ final SparseBooleanArray changedUsers = new SparseBooleanArray();
+ mPm.clearPackagePreferredActivitiesLPw(
+ packageName, changedUsers, UserHandle.USER_ALL);
+ mPm.mInjector.getBackgroundHandler().post(() -> {
+ if (changedUsers.size() > 0) {
+ preferredActivityHelper.updateDefaultHomeNotLocked(mPm.snapshotComputer(),
+ changedUsers);
+ mBroadcastHelper.sendPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
+ }
+ });
+ // Step 5: inform PermissionManager.
+ // This has to be done after the removal from mSettings in removePackageDataLIF.
+ }
+ } else {
+ if (DEBUG_REMOVE) {
+ Slog.d(TAG, "Clear package:" + packageName + " state for user:" + userId);
}
- mAppDataHelper.clearKeystoreData(nextUserId, ps.getAppId());
- preferredActivityHelper.clearPackagePreferredActivities(ps.getPackageName(),
- nextUserId);
- mPm.mDomainVerificationManager.clearPackageForUser(ps.getPackageName(), nextUserId);
+ // Step 3: inform DomainVerificationManager.
+ mPm.mDomainVerificationManager.clearPackageForUser(packageName, userId);
+ // Step 4: clear perferred activities.
+ preferredActivityHelper.clearPackagePreferredActivities(packageName, userId);
+ // Step 5: inform PermissionManager.
+ List<AndroidPackage> sharedUserPkgs =
+ sus != null ? sus.getPackages() : Collections.emptyList();
+ mPermissionManager.onPackageUninstalled(packageName, ps.getAppId(), ps, pkg,
+ sharedUserPkgs, userId);
}
- mPermissionManager.onPackageUninstalled(ps.getPackageName(), ps.getAppId(), ps, pkg,
- sharedUserPkgs, userId);
+
+ // Step 6: detroy keystore data.
+ mPm.mInjector.getBackgroundHandler().post(() -> {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
+ "clearKeystoreData:" + ps.getAppId() + " for user: " + userId);
+ mAppDataHelper.clearKeystoreData(userId, ps.getAppId());
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ });
}
// Called to clean up disabled system packages
@@ -297,10 +360,7 @@ final class RemovePackageHelper {
}
/*
- * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
- * flag is not set, the data directory is removed as well.
- * make sure this flag is set for partially installed apps. If not it's meaningless to
- * delete a partially installed application.
+ * This method deletes the package from internal data structures such as mPackages / mSettings.
*/
@GuardedBy("mPm.mInstallLock")
public void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
@@ -310,7 +370,11 @@ final class RemovePackageHelper {
// Retrieve object to delete permissions for shared user later on
final AndroidPackage deletedPkg = deletedPs.getPkg();
- removePackageLI(deletedPs.getPackageName(), (flags & PackageManager.DELETE_CHATTY) != 0);
+ // Delete all the data and states related to this package.
+ clearPackageStateForUserLIF(deletedPs, UserHandle.USER_ALL, flags);
+
+ // Delete from mPackages
+ removePackageLI(packageName, (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
@@ -320,40 +384,16 @@ final class RemovePackageHelper {
}
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
- final AndroidPackage resolvedPkg;
- if (deletedPkg != null) {
- resolvedPkg = deletedPkg;
- } else {
- // We don't have a parsed package when it lives on an ejected
- // adopted storage device, so fake something together
- resolvedPkg = PackageImpl.buildFakeForDeletion(deletedPs.getPackageName(),
- deletedPs.getVolumeUuid());
- }
- mAppDataHelper.destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
- FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
- mAppDataHelper.destroyAppProfilesLIF(resolvedPkg.getPackageName());
- }
-
- int removedAppId = -1;
-
- // writer
- if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+ // Delete from mSettings
final SparseBooleanArray changedUsers = new SparseBooleanArray();
synchronized (mPm.mLock) {
- mPm.mDomainVerificationManager.clearPackage(deletedPs.getPackageName());
- mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
- mPm.mInjector.getUpdateOwnershipHelper().removeUpdateOwnerDenyList(packageName);
- final Computer snapshot = mPm.snapshotComputer();
- mPm.mAppsFilter.removePackage(snapshot,
- snapshot.getPackageStateInternal(packageName));
- removedAppId = mPm.mSettings.removePackageLPw(packageName);
- outInfo.mRemovedAppId = removedAppId;
-
+ mPm.mSettings.removePackageLPw(packageName);
+ outInfo.mIsAppIdRemoved = true;
if (!mPm.mSettings.isDisabledSystemPackageLPr(packageName)) {
+ final SharedUserSetting sus = mPm.mSettings.getSharedUserSettingLPr(deletedPs);
// If we don't have a disabled system package to reinstall, the package is
// really gone and its permission state should be removed.
- SharedUserSetting sus = mPm.mSettings.getSharedUserSettingLPr(deletedPs);
- List<AndroidPackage> sharedUserPkgs =
+ final List<AndroidPackage> sharedUserPkgs =
sus != null ? sus.getPackages() : Collections.emptyList();
mPermissionManager.onPackageUninstalled(packageName, deletedPs.getAppId(),
deletedPs, deletedPkg, sharedUserPkgs, UserHandle.USER_ALL);
@@ -362,20 +402,8 @@ final class RemovePackageHelper {
mPm.mSettings.checkAndConvertSharedUserSettingsLPw(sus);
}
}
- mPm.clearPackagePreferredActivitiesLPw(
- deletedPs.getPackageName(), changedUsers, UserHandle.USER_ALL);
-
mPm.mSettings.removeRenamedPackageLPw(deletedPs.getRealName());
}
- if (changedUsers.size() > 0) {
- mPm.mInjector.getBackgroundHandler().post(() -> {
- final PreferredActivityHelper preferredActivityHelper =
- new PreferredActivityHelper(mPm, mBroadcastHelper);
- preferredActivityHelper.updateDefaultHomeNotLocked(mPm.snapshotComputer(),
- changedUsers);
- mBroadcastHelper.sendPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
- });
- }
} else if (!deletedPs.isSystem() && !outInfo.mIsUpdate
&& outInfo.mRemovedUsers != null && !deletedPs.isExternalStorage()) {
// For non-system uninstalls with DELETE_KEEP_DATA, set the installed state to false
@@ -394,6 +422,7 @@ final class RemovePackageHelper {
deletedPs.setInstalled(/* installed= */ false, userId);
}
}
+
// make sure to preserve per-user installed state if this removal was just
// a downgrade of a system app to the factory package
boolean installedStateChanged = false;
@@ -425,20 +454,6 @@ final class RemovePackageHelper {
mPm.mSettings.writeKernelMappingLPr(deletedPs);
}
}
-
- if (removedAppId != -1) {
- // A user ID was deleted here. Go through all users and remove it from KeyStore.
- final int appIdToRemove = removedAppId;
- mPm.mInjector.getBackgroundHandler().post(() -> {
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
- "clearKeystoreData:" + appIdToRemove);
- mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, appIdToRemove);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- });
- }
}
void cleanUpResources(File codeFile, String[] instructionSets) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index cfbaae3d0f30..cdf1f949a2d8 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -51,6 +51,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.overlay.OverlayPaths;
import android.net.Uri;
@@ -1956,7 +1957,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
ArchiveState archiveState = null;
int packageDepth = parser.getDepth();
- ArrayMap<String, SuspendParams> suspendParamsMap = null;
+ ArrayMap<UserPackage, SuspendParams> suspendParamsMap = null;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > packageDepth)) {
@@ -1983,18 +1984,15 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
parser);
break;
case TAG_SUSPEND_PARAMS:
- final String suspendingPackage = parser.getAttributeValue(null,
- ATTR_SUSPENDING_PACKAGE);
- if (suspendingPackage == null) {
- Slog.wtf(TAG, "No suspendingPackage found inside tag "
- + TAG_SUSPEND_PARAMS);
+ Map.Entry<UserPackage, SuspendParams> entry =
+ readSuspensionParamsLPr(userId, parser);
+ if (entry == null) {
continue;
}
if (suspendParamsMap == null) {
suspendParamsMap = new ArrayMap<>();
}
- suspendParamsMap.put(suspendingPackage,
- SuspendParams.restoreFromXml(parser));
+ suspendParamsMap.put(entry.getKey(), entry.getValue());
break;
case TAG_ARCHIVE_STATE:
archiveState = parseArchiveState(parser);
@@ -2016,7 +2014,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
oldSuspendedLauncherExtras,
false /* quarantined */);
suspendParamsMap = new ArrayMap<>();
- suspendParamsMap.put(oldSuspendingPackage, suspendParams);
+ suspendParamsMap.put(
+ UserPackage.of(userId, oldSuspendingPackage), suspendParams);
}
if (blockUninstall) {
@@ -2058,6 +2057,20 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
}
}
+ @Nullable
+ private static Map.Entry<UserPackage, SuspendParams> readSuspensionParamsLPr(
+ int userId, TypedXmlPullParser parser) throws IOException {
+ final String suspendingPackage = parser.getAttributeValue(null, ATTR_SUSPENDING_PACKAGE);
+ if (suspendingPackage == null) {
+ Slog.wtf(TAG, "No suspendingPackage found inside tag " + TAG_SUSPEND_PARAMS);
+ return null;
+ }
+ final int suspendingUserId = userId;
+ return Map.entry(
+ UserPackage.of(suspendingUserId, suspendingPackage),
+ SuspendParams.restoreFromXml(parser));
+ }
+
private static ArchiveState parseArchiveState(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
String installerTitle = parser.getAttributeValue(null,
@@ -2414,10 +2427,11 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
}
if (ustate.isSuspended()) {
for (int i = 0; i < ustate.getSuspendParams().size(); i++) {
- final String suspendingPackage = ustate.getSuspendParams().keyAt(i);
+ final UserPackage suspendingPackage =
+ ustate.getSuspendParams().keyAt(i);
serializer.startTag(null, TAG_SUSPEND_PARAMS);
serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
- suspendingPackage);
+ suspendingPackage.packageName);
final SuspendParams params =
ustate.getSuspendParams().valueAt(i);
if (params != null) {
@@ -2556,7 +2570,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
outPs.getUsesSdkLibraries(), libName));
outPs.setUsesSdkLibrariesVersionsMajor(ArrayUtils.appendLong(
outPs.getUsesSdkLibrariesVersionsMajor(), libVersion));
- outPs.setUsesSdkLibrariesOptional(PackageImpl.appendBoolean(
+ outPs.setUsesSdkLibrariesOptional(ArrayUtils.appendBoolean(
outPs.getUsesSdkLibrariesOptional(), optional));
}
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index c2a960a95394..4e70cc52ef90 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -27,10 +27,10 @@ import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.content.Intent;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.os.Binder;
import android.os.Bundle;
import android.os.PersistableBundle;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
@@ -88,8 +88,8 @@ public final class SuspendPackageHelper {
* @param dialogInfo An optional {@link SuspendDialogInfo} object describing the dialog that
* should be shown to the user when they try to launch a suspended app.
* Ignored if {@code suspended} is false.
- * @param callingPackage The caller's package name.
- * @param userId The user where packages reside.
+ * @param suspendingPackage The caller's package name.
+ * @param targetUserId The user where packages reside.
* @param callingUid The caller's uid.
* @return The names of failed packages.
*/
@@ -97,14 +97,14 @@ public final class SuspendPackageHelper {
String[] setPackagesSuspended(@NonNull Computer snapshot, @Nullable String[] packageNames,
boolean suspended, @Nullable PersistableBundle appExtras,
@Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo,
- @NonNull String callingPackage, @UserIdInt int userId, int callingUid,
+ @NonNull UserPackage suspendingPackage, @UserIdInt int targetUserId, int callingUid,
boolean quarantined) {
if (ArrayUtils.isEmpty(packageNames)) {
return packageNames;
}
- if (suspended && !quarantined && !isSuspendAllowedForUser(snapshot, userId,
- callingUid)) {
- Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
+ if (suspended && !quarantined
+ && !isSuspendAllowedForUser(snapshot, targetUserId, callingUid)) {
+ Slog.w(TAG, "Cannot suspend due to restrictions on user " + targetUserId);
return packageNames;
}
@@ -119,19 +119,21 @@ public final class SuspendPackageHelper {
final IntArray changedUids = new IntArray(packageNames.length);
final boolean[] canSuspend = suspended
- ? canSuspendPackageForUser(snapshot, packageNames, userId, callingUid)
+ ? canSuspendPackageForUser(snapshot, packageNames, targetUserId, callingUid)
: null;
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
- if (callingPackage.equals(packageName)) {
- Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
+ if (suspendingPackage.packageName.equals(packageName)
+ && suspendingPackage.userId == targetUserId) {
+ Slog.w(TAG, "Suspending package: " + suspendingPackage + " trying to "
+ (suspended ? "" : "un") + "suspend itself. Ignoring");
unmodifiablePackages.add(packageName);
continue;
}
final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
- if (packageState == null || !packageState.getUserStateOrDefault(userId).isInstalled()
- || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
+ if (packageState == null
+ || !packageState.getUserStateOrDefault(targetUserId).isInstalled()
+ || snapshot.shouldFilterApplication(packageState, callingUid, targetUserId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
+ ". Skipping suspending/un-suspending.");
unmodifiablePackages.add(packageName);
@@ -142,34 +144,34 @@ public final class SuspendPackageHelper {
continue;
}
- final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
- packageState.getUserStateOrDefault(userId).getSuspendParams();
+ final WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
+ packageState.getUserStateOrDefault(targetUserId).getSuspendParams();
final SuspendParams oldSuspendParams = suspendParamsMap == null
- ? null : suspendParamsMap.get(callingPackage);
+ ? null : suspendParamsMap.get(suspendingPackage);
boolean changed = !Objects.equals(oldSuspendParams, newSuspendParams);
if (suspended && !changed) {
// Carried over API behavior, must notify change even if no change
notifyPackagesList.add(packageName);
notifyUids.add(
- UserHandle.getUid(userId, packageState.getAppId()));
+ UserHandle.getUid(targetUserId, packageState.getAppId()));
continue;
}
- // If only the callingPackage is suspending this package,
+ // If only the suspendingPackage is suspending this package,
// it will be unsuspended when this change is committed
boolean packageUnsuspended = !suspended
&& CollectionUtils.size(suspendParamsMap) == 1
- && suspendParamsMap.containsKey(callingPackage);
+ && suspendParamsMap.containsKey(suspendingPackage);
if (suspended || packageUnsuspended) {
// Always notify of a suspend call + notify when fully unsuspended
notifyPackagesList.add(packageName);
- notifyUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ notifyUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
}
if (changed) {
changedPackagesList.add(packageName);
- changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ changedUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
} else {
Slog.w(TAG, "No change is needed for package: " + packageName
+ ". Skipping suspending/un-suspending.");
@@ -181,11 +183,11 @@ public final class SuspendPackageHelper {
for (int index = 0; index < size; index++) {
final String packageName = changedPackagesList.valueAt(index);
final PackageUserStateWrite userState = mutator.forPackage(packageName)
- .userState(userId);
+ .userState(targetUserId);
if (suspended) {
- userState.putSuspendParams(callingPackage, newSuspendParams);
+ userState.putSuspendParams(suspendingPackage, newSuspendParams);
} else {
- userState.removeSuspension(callingPackage);
+ userState.removeSuspension(suspendingPackage);
}
}
});
@@ -197,17 +199,17 @@ public final class SuspendPackageHelper {
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
suspended ? Intent.ACTION_PACKAGES_SUSPENDED
: Intent.ACTION_PACKAGES_UNSUSPENDED,
- changedPackages, notifyUids.toArray(), quarantined, userId);
+ changedPackages, notifyUids.toArray(), quarantined, targetUserId);
mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, changedPackages,
- suspended, userId);
- mPm.scheduleWritePackageRestrictions(userId);
+ suspended, targetUserId);
+ mPm.scheduleWritePackageRestrictions(targetUserId);
}
// Send the suspension changed broadcast to ensure suspension state is not stale.
if (!changedPackagesList.isEmpty()) {
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
changedPackagesList.toArray(new String[0]), changedUids.toArray(), quarantined,
- userId);
+ targetUserId);
}
return unmodifiablePackages.toArray(new String[0]);
}
@@ -216,19 +218,19 @@ public final class SuspendPackageHelper {
* Returns the names in the {@code packageNames} which can not be suspended by the caller.
*
* @param packageNames The names of packages to check.
- * @param userId The user where packages reside.
+ * @param targetUserId The user where packages reside.
* @param callingUid The caller's uid.
* @return The names of packages which are Unsuspendable.
*/
@NonNull
String[] getUnsuspendablePackagesForUser(@NonNull Computer snapshot,
- @NonNull String[] packageNames, @UserIdInt int userId, int callingUid) {
- if (!isSuspendAllowedForUser(snapshot, userId, callingUid)) {
- Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
+ @NonNull String[] packageNames, @UserIdInt int targetUserId, int callingUid) {
+ if (!isSuspendAllowedForUser(snapshot, targetUserId, callingUid)) {
+ Slog.w(TAG, "Cannot suspend due to restrictions on user " + targetUserId);
return packageNames;
}
final ArraySet<String> unactionablePackages = new ArraySet<>();
- final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, userId,
+ final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, targetUserId,
callingUid);
for (int i = 0; i < packageNames.length; i++) {
if (!canSuspend[i]) {
@@ -237,7 +239,7 @@ public final class SuspendPackageHelper {
}
final PackageStateInternal packageState =
snapshot.getPackageStateForInstalledAndFiltered(
- packageNames[i], callingUid, userId);
+ packageNames[i], callingUid, targetUserId);
if (packageState == null) {
Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
unactionablePackages.add(packageNames[i]);
@@ -285,30 +287,31 @@ public final class SuspendPackageHelper {
* @param packagesToChange The packages on which the suspension are to be removed.
* @param suspendingPackagePredicate A predicate identifying the suspending packages whose
* suspensions will be removed.
- * @param userId The user for which the changes are taking place.
+ * @param targetUserId The user for which the changes are taking place.
*/
void removeSuspensionsBySuspendingPackage(@NonNull Computer snapshot,
@NonNull String[] packagesToChange,
- @NonNull Predicate<String> suspendingPackagePredicate, int userId) {
+ @NonNull Predicate<UserPackage> suspendingPackagePredicate, int targetUserId) {
final List<String> unsuspendedPackages = new ArrayList<>();
final IntArray unsuspendedUids = new IntArray();
- final ArrayMap<String, ArraySet<String>> pkgToSuspendingPkgsToCommit = new ArrayMap<>();
+ final ArrayMap<String, ArraySet<UserPackage>> pkgToSuspendingPkgsToCommit =
+ new ArrayMap<>();
for (String packageName : packagesToChange) {
final PackageStateInternal packageState =
snapshot.getPackageStateInternal(packageName);
final PackageUserStateInternal packageUserState = packageState == null
- ? null : packageState.getUserStateOrDefault(userId);
+ ? null : packageState.getUserStateOrDefault(targetUserId);
if (packageUserState == null || !packageUserState.isSuspended()) {
continue;
}
- WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+ WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
packageUserState.getSuspendParams();
int countRemoved = 0;
for (int index = 0; index < suspendParamsMap.size(); index++) {
- String suspendingPackage = suspendParamsMap.keyAt(index);
+ UserPackage suspendingPackage = suspendParamsMap.keyAt(index);
if (suspendingPackagePredicate.test(suspendingPackage)) {
- ArraySet<String> suspendingPkgsToCommit =
+ ArraySet<UserPackage> suspendingPkgsToCommit =
pkgToSuspendingPkgsToCommit.get(packageName);
if (suspendingPkgsToCommit == null) {
suspendingPkgsToCommit = new ArraySet<>();
@@ -322,31 +325,33 @@ public final class SuspendPackageHelper {
// Everything would be removed and package unsuspended
if (countRemoved == suspendParamsMap.size()) {
unsuspendedPackages.add(packageState.getPackageName());
- unsuspendedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ unsuspendedUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
}
}
mPm.commitPackageStateMutation(null, mutator -> {
for (int mapIndex = 0; mapIndex < pkgToSuspendingPkgsToCommit.size(); mapIndex++) {
String packageName = pkgToSuspendingPkgsToCommit.keyAt(mapIndex);
- ArraySet<String> packagesToRemove = pkgToSuspendingPkgsToCommit.valueAt(mapIndex);
- PackageUserStateWrite userState = mutator.forPackage(packageName).userState(userId);
+ ArraySet<UserPackage> packagesToRemove =
+ pkgToSuspendingPkgsToCommit.valueAt(mapIndex);
+ PackageUserStateWrite userState =
+ mutator.forPackage(packageName).userState(targetUserId);
for (int setIndex = 0; setIndex < packagesToRemove.size(); setIndex++) {
userState.removeSuspension(packagesToRemove.valueAt(setIndex));
}
}
});
- mPm.scheduleWritePackageRestrictions(userId);
+ mPm.scheduleWritePackageRestrictions(targetUserId);
final Computer newSnapshot = mPm.snapshotComputer();
if (!unsuspendedPackages.isEmpty()) {
final String[] packageArray = unsuspendedPackages.toArray(
new String[unsuspendedPackages.size()]);
mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, packageArray,
- false, userId);
+ false, targetUserId);
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
Intent.ACTION_PACKAGES_UNSUSPENDED,
- packageArray, unsuspendedUids.toArray(), false, userId);
+ packageArray, unsuspendedUids.toArray(), false, targetUserId);
}
}
@@ -404,7 +409,7 @@ public final class SuspendPackageHelper {
* @return The name of suspending package.
*/
@Nullable
- String getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
+ UserPackage getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
int userId, int callingUid) {
final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
@@ -417,13 +422,13 @@ public final class SuspendPackageHelper {
return null;
}
- String suspendingPackage = null;
- String suspendedBySystem = null;
- String qasPackage = null;
+ UserPackage suspendingPackage = null;
+ UserPackage suspendedBySystem = null;
+ UserPackage qasPackage = null;
for (int i = 0; i < userState.getSuspendParams().size(); i++) {
suspendingPackage = userState.getSuspendParams().keyAt(i);
var suspendParams = userState.getSuspendParams().valueAt(i);
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+ if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage.packageName)) {
suspendedBySystem = suspendingPackage;
}
if (suspendParams.isQuarantined() && qasPackage == null) {
@@ -451,7 +456,7 @@ public final class SuspendPackageHelper {
*/
@Nullable
SuspendDialogInfo getSuspendedDialogInfo(@NonNull Computer snapshot,
- @NonNull String suspendedPackage, @NonNull String suspendingPackage, int userId,
+ @NonNull String suspendedPackage, @NonNull UserPackage suspendingPackage, int userId,
int callingUid) {
final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
@@ -464,7 +469,7 @@ public final class SuspendPackageHelper {
return null;
}
- final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+ final WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
userState.getSuspendParams();
if (suspendParamsMap == null) {
return null;
@@ -493,34 +498,36 @@ public final class SuspendPackageHelper {
* be suspended or not.
*
* @param packageNames The package names to check suspendability for.
- * @param userId The user to check in
+ * @param targetUserId The user to check in
* @param callingUid The caller's uid.
* @return An array containing results of the checks
*/
@NonNull
boolean[] canSuspendPackageForUser(@NonNull Computer snapshot, @NonNull String[] packageNames,
- int userId, int callingUid) {
+ int targetUserId, int callingUid) {
final boolean[] canSuspend = new boolean[packageNames.length];
- final boolean isCallerOwner = isCallerDeviceOrProfileOwner(snapshot, userId, callingUid);
+ final boolean isCallerOwner =
+ isCallerDeviceOrProfileOwner(snapshot, targetUserId, callingUid);
final long token = Binder.clearCallingIdentity();
try {
final DefaultAppProvider defaultAppProvider = mInjector.getDefaultAppProvider();
- final String activeLauncherPackageName = defaultAppProvider.getDefaultHome(userId);
- final String dialerPackageName = defaultAppProvider.getDefaultDialer(userId);
+ final String activeLauncherPackageName =
+ defaultAppProvider.getDefaultHome(targetUserId);
+ final String dialerPackageName = defaultAppProvider.getDefaultDialer(targetUserId);
final String requiredInstallerPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_INSTALLER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_INSTALLER, targetUserId);
final String requiredUninstallerPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_UNINSTALLER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_UNINSTALLER, targetUserId);
final String requiredVerifierPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_VERIFIER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_VERIFIER, targetUserId);
final String requiredPermissionControllerPackage =
getKnownPackageName(snapshot, KnownPackages.PACKAGE_PERMISSION_CONTROLLER,
- userId);
+ targetUserId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
final String packageName = packageNames[i];
- if (mPm.isPackageDeviceAdmin(packageName, userId)) {
+ if (mPm.isPackageDeviceAdmin(packageName, targetUserId)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": has an active device admin");
continue;
@@ -555,12 +562,12 @@ public final class SuspendPackageHelper {
+ "\": required for permissions management");
continue;
}
- if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ if (mProtectedPackages.isPackageStateProtected(targetUserId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": protected package");
continue;
}
- if (!isCallerOwner && snapshot.getBlockUninstall(userId, packageName)) {
+ if (!isCallerOwner && snapshot.getBlockUninstall(targetUserId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": blocked by admin");
continue;
@@ -572,7 +579,7 @@ public final class SuspendPackageHelper {
PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
AndroidPackage pkg = packageState == null ? null : packageState.getPkg();
if (pkg != null) {
- final int uid = UserHandle.getUid(userId, packageState.getAppId());
+ final int uid = UserHandle.getUid(targetUserId, packageState.getAppId());
// Cannot suspend SDK libs as they are controlled by SDK manager.
if (pkg.isSdkLibrary()) {
Slog.w(TAG, "Cannot suspend package: " + packageName
@@ -614,20 +621,6 @@ public final class SuspendPackageHelper {
== AppOpsManager.MODE_ALLOWED;
}
- /**
- * Suspends packages on behalf of an admin.
- *
- * @return array of packages that are unsuspendable, either because admin is not allowed to
- * suspend them (e.g. current dialer) or there was other problem (e.g. package not found).
- */
- public String[] setPackagesSuspendedByAdmin(
- Computer snapshot, int userId, String[] packageNames, boolean suspend) {
- return setPackagesSuspended(snapshot, packageNames, suspend,
- null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */,
- PackageManagerService.PLATFORM_PACKAGE_NAME, userId, Process.SYSTEM_UID,
- false /* quarantined */);
- }
-
private String getKnownPackageName(@NonNull Computer snapshot,
@KnownPackages.KnownPackage int knownPackage, int userId) {
final String[] knownPackages =
@@ -635,14 +628,15 @@ public final class SuspendPackageHelper {
return knownPackages.length > 0 ? knownPackages[0] : null;
}
- private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int userId,
+ private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int targetUserId,
int callingUid) {
if (callingUid == SYSTEM_UID) {
return true;
}
- final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
+ final String ownerPackage =
+ mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(targetUserId);
if (ownerPackage != null) {
- return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, userId,
+ return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, targetUserId,
callingUid);
}
return false;
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 7386301bdd6e..14db70e5f72e 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -306,7 +306,6 @@ public final class UserTypeFactory {
.setDarkThemeBadgeColors(
R.color.white)
.setDefaultRestrictions(getDefaultProfileRestrictions())
- .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings())
.setDefaultUserProperties(new UserProperties.Builder()
.setStartWithParent(true)
.setCredentialShareableWithParent(true)
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 fa54f0ba18cd..d0fe9647618a 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -28,6 +28,7 @@ import android.content.pm.ConfigurationInfo;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
@@ -474,7 +475,34 @@ public class PackageInfoUtils {
}
info.sharedLibraryFiles = usesLibraryFiles.isEmpty()
? null : usesLibraryFiles.toArray(new String[0]);
- info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+
+
+ if (!Flags.sdkLibIndependence()) {
+ info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+ info.optionalSharedLibraryInfos = null;
+ } else {
+ // sharedLibraryInfos contains all shared libraries that the app depends on (including
+ // the optional sdk libraries)
+ info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+ String[] libsNames = pkgSetting.getUsesSdkLibraries();
+ boolean[] libsOptional = pkgSetting.getUsesSdkLibrariesOptional();
+ List<SharedLibraryInfo> optionalSdkLibraries = null;
+ if (!ArrayUtils.isEmpty(libsOptional) && !ArrayUtils.isEmpty(libsNames)
+ && libsNames.length == libsOptional.length) {
+ for (SharedLibraryInfo info1 : usesLibraryInfos) {
+ if (info1.getType() == SharedLibraryInfo.TYPE_SDK_PACKAGE) {
+ int index = ArrayUtils.indexOf(libsNames, info1.getName());
+ if (index >= 0 && libsOptional[index]) {
+ if (optionalSdkLibraries == null) {
+ optionalSdkLibraries = new ArrayList<>();
+ }
+ optionalSdkLibraries.add(info1);
+ }
+ }
+ }
+ }
+ info.optionalSharedLibraryInfos = optionalSdkLibraries;
+ }
if (info.category == ApplicationInfo.CATEGORY_UNDEFINED) {
info.category = pkgSetting.getCategoryOverride();
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
index 2f4ad2d8fcc6..15b693cf72f8 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.util.ArraySet;
import android.util.Pair;
@@ -173,7 +174,7 @@ class PackageUserStateDefault implements PackageUserStateInternal {
@Nullable
@Override
- public WatchedArrayMap<String, SuspendParams> getSuspendParams() {
+ public WatchedArrayMap<UserPackage, SuspendParams> getSuspendParams() {
return null;
}
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 c5ef5257ddd5..7a5a14d8d3c2 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -121,7 +122,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
@Nullable
- private WatchedArrayMap<String, SuspendParams> mSuspendParams;
+ private WatchedArrayMap<UserPackage, SuspendParams> mSuspendParams;
@Nullable
private WatchedArrayMap<ComponentName, Pair<String, Integer>> mComponentLabelIconOverrideMap;
@@ -369,7 +370,10 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
return !CollectionUtils.isEmpty(mSuspendParams);
}
- public PackageUserStateImpl putSuspendParams(@NonNull String suspendingPackage,
+ /**
+ * Adds or updates suspension params by the given package.
+ */
+ public PackageUserStateImpl putSuspendParams(@NonNull UserPackage suspendingPackage,
@Nullable SuspendParams suspendParams) {
if (mSuspendParams == null) {
mSuspendParams = new WatchedArrayMap<>();
@@ -384,7 +388,10 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
return this;
}
- public PackageUserStateImpl removeSuspension(@NonNull String suspendingPackage) {
+ /**
+ * Removes suspension by the given package.
+ */
+ public PackageUserStateImpl removeSuspension(@NonNull UserPackage suspendingPackage) {
if (mSuspendParams != null) {
mSuspendParams.remove(suspendingPackage);
onChanged();
@@ -565,7 +572,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
public @NonNull PackageUserStateImpl setSuspendParams(
- @NonNull ArrayMap<String, SuspendParams> value) {
+ @NonNull ArrayMap<UserPackage, SuspendParams> value) {
if (value == null) {
return this;
}
@@ -778,7 +785,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
@DataClass.Generated.Member
- public @Nullable WatchedArrayMap<String,SuspendParams> getSuspendParams() {
+ public @Nullable WatchedArrayMap<UserPackage,SuspendParams> getSuspendParams() {
return mSuspendParams;
}
@@ -830,7 +837,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
@DataClass.Generated.Member
- public @NonNull PackageUserStateImpl setSuspendParams(@NonNull WatchedArrayMap<String,SuspendParams> value) {
+ public @NonNull PackageUserStateImpl setSuspendParams(@NonNull WatchedArrayMap<UserPackage,SuspendParams> value) {
mSuspendParams = value;
return this;
}
@@ -909,10 +916,10 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
}
@DataClass.Generated(
- time = 1701470095849L,
+ time = 1701864813354L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
- 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 long mDeDataInode\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 setDeDataInode(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()\npublic @java.lang.Override boolean isQuarantined()\npublic @java.lang.Override boolean dataExists()\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)")
+ 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 long mDeDataInode\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<android.content.pm.UserPackage,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(android.content.pm.UserPackage,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(android.content.pm.UserPackage)\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 setDeDataInode(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<android.content.pm.UserPackage,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()\npublic @java.lang.Override boolean isQuarantined()\npublic @java.lang.Override boolean dataExists()\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/pm/pkg/PackageUserStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
index 46cc830130ef..f8d745cb7fbf 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
@@ -19,6 +19,7 @@ package com.android.server.pm.pkg;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
+import android.content.pm.UserPackage;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.util.Pair;
@@ -38,7 +39,7 @@ public interface PackageUserStateInternal extends PackageUserState, FrameworkPac
// TODO: Make non-null with emptyMap()
@Nullable
- WatchedArrayMap<String, SuspendParams> getSuspendParams();
+ WatchedArrayMap<UserPackage, SuspendParams> getSuspendParams();
@Nullable
WatchedArraySet<String> getDisabledComponentsNoCopy();
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
index 8430cf7a0d11..253eb4006122 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.util.ArraySet;
@@ -349,7 +350,7 @@ public class PackageStateMutator {
@NonNull
@Override
- public PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
+ public PackageUserStateWrite putSuspendParams(@NonNull UserPackage suspendingPackage,
@Nullable SuspendParams suspendParams) {
if (mUserState != null) {
mUserState.putSuspendParams(suspendingPackage, suspendParams);
@@ -359,7 +360,7 @@ public class PackageStateMutator {
@NonNull
@Override
- public PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage) {
+ public PackageUserStateWrite removeSuspension(@NonNull UserPackage suspendingPackage) {
if (mUserState != null) {
mUserState.removeSuspension(suspendingPackage);
}
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
index 0c6c6723b79b..f6b21045a8bb 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import com.android.server.pm.pkg.PackageUserStateImpl;
@@ -38,11 +39,11 @@ public interface PackageUserStateWrite {
@PackageManager.DistractionRestriction int restrictionFlags);
@NonNull
- PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
+ PackageUserStateWrite putSuspendParams(@NonNull UserPackage suspendingPackage,
@Nullable SuspendParams suspendParams);
@NonNull
- PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage);
+ PackageUserStateWrite removeSuspension(@NonNull UserPackage suspendingPackage);
@NonNull
PackageUserStateWrite setHidden(boolean hidden);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 6f2750767094..d903ad4d9f0d 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -41,7 +41,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
@@ -2081,6 +2080,45 @@ public final class TvInputManagerService extends SystemService {
}
@Override
+ public void stopPlayback(IBinder sessionToken, int mode, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "stopPlayback");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId).stopPlayback(
+ mode);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in stopPlayback(mode)", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void startPlayback(IBinder sessionToken, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "stopPlayback");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId).startPlayback();
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in startPlayback()", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void timeShiftPlay(IBinder sessionToken, final Uri recordedProgramUri, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 315e7d85df24..4b55bec928c7 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -18,17 +18,17 @@ package com.android.server.wm;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.app.Activity.FULLSCREEN_MODE_REQUEST_ENTER;
+import static android.app.Activity.FULLSCREEN_MODE_REQUEST_EXIT;
import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.INVALID_WINDOWING_MODE;
import static android.app.FullscreenRequestHandler.REMOTE_CALLBACK_RESULT_KEY;
import static android.app.FullscreenRequestHandler.RESULT_APPROVED;
-import static android.app.FullscreenRequestHandler.RESULT_FAILED_NOT_DEFAULT_FREEFORM;
-import static android.app.FullscreenRequestHandler.RESULT_FAILED_NOT_IN_FREEFORM;
import static android.app.FullscreenRequestHandler.RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY;
import static android.app.FullscreenRequestHandler.RESULT_FAILED_NOT_TOP_FOCUSED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
@@ -1092,19 +1092,14 @@ class ActivityClientController extends IActivityClientController.Stub {
private @FullscreenRequestHandler.RequestResult int validateMultiwindowFullscreenRequestLocked(
Task topFocusedRootTask, int fullscreenRequest, ActivityRecord requesterActivity) {
- // If the mode is not by default freeform, the freeform will be a user-driven event.
- if (topFocusedRootTask.getParent().getWindowingMode() != WINDOWING_MODE_FREEFORM) {
- return RESULT_FAILED_NOT_DEFAULT_FREEFORM;
+ if (requesterActivity.getWindowingMode() == WINDOWING_MODE_PINNED) {
+ return RESULT_APPROVED;
}
// If this is not coming from the currently top-most activity, reject the request.
if (requesterActivity != topFocusedRootTask.getTopMostActivity()) {
return RESULT_FAILED_NOT_TOP_FOCUSED;
}
- if (fullscreenRequest == FULLSCREEN_MODE_REQUEST_ENTER) {
- if (topFocusedRootTask.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
- return RESULT_FAILED_NOT_IN_FREEFORM;
- }
- } else {
+ if (fullscreenRequest == FULLSCREEN_MODE_REQUEST_EXIT) {
if (topFocusedRootTask.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
return RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index f9d344bd7e31..1b45c1b4f3f1 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -48,6 +48,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -335,19 +336,19 @@ class ActivityStartInterceptor {
return false;
}
final String suspendedPackage = mAInfo.applicationInfo.packageName;
- final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+ final UserPackage suspender = pmi.getSuspendingPackage(suspendedPackage, mUserId);
+ if (suspender != null && PLATFORM_PACKAGE_NAME.equals(suspender.packageName)) {
return interceptSuspendedByAdminPackage();
}
final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage,
- suspendingPackage, mUserId);
+ suspender, mUserId);
final Bundle crossProfileOptions = hasCrossProfileAnimation()
? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
: null;
final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
FLAG_IMMUTABLE);
mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
- suspendingPackage, dialogInfo, crossProfileOptions, target, mUserId);
+ suspender, dialogInfo, crossProfileOptions, target, mUserId);
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4b0177a36ebe..630b9e139456 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -84,7 +84,9 @@ import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENS
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.window.flags.Flags.balDontBringExistingBackgroundTaskStackToFg;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -140,6 +142,8 @@ import com.android.server.wm.LaunchParamsController.LaunchParams;
import com.android.server.wm.TaskFragment.EmbeddingCheckResult;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.text.DateFormat;
import java.util.Date;
@@ -230,7 +234,26 @@ class ActivityStarter {
private boolean mIsTaskCleared;
private boolean mMovedToFront;
private boolean mNoAnimation;
- private boolean mAvoidMoveToFront;
+
+ // TODO mAvoidMoveToFront before V is changed from a boolean to a int code mCanMoveToFrontCode
+ // for the purpose of attribution of new BAL V feature. This should be reverted back to the
+ // boolean flag post V.
+ @IntDef(prefix = {"MOVE_TO_FRONT_"}, value = {
+ MOVE_TO_FRONT_ALLOWED,
+ MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS,
+ MOVE_TO_FRONT_AVOID_LEGACY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MoveToFrontCode {}
+
+ // Allows a task move to front.
+ private static final int MOVE_TO_FRONT_ALLOWED = 0;
+ // Avoid a task move to front because the Pending Intent that starts the activity only
+ // its creator has the BAL privilege, its sender does not.
+ private static final int MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS = 1;
+ // Avoid a task move to front because of all other legacy reasons.
+ private static final int MOVE_TO_FRONT_AVOID_LEGACY = 2;
+ private @MoveToFrontCode int mCanMoveToFrontCode = MOVE_TO_FRONT_ALLOWED;
private boolean mFrozeTaskList;
private boolean mTransientLaunch;
// The task which was above the targetTask before starting this activity. null if the targetTask
@@ -642,7 +665,7 @@ class ActivityStarter {
mIsTaskCleared = starter.mIsTaskCleared;
mMovedToFront = starter.mMovedToFront;
mNoAnimation = starter.mNoAnimation;
- mAvoidMoveToFront = starter.mAvoidMoveToFront;
+ mCanMoveToFrontCode = starter.mCanMoveToFrontCode;
mFrozeTaskList = starter.mFrozeTaskList;
mVoiceSession = starter.mVoiceSession;
@@ -1499,6 +1522,14 @@ class ActivityStarter {
return result;
}
+ private boolean avoidMoveToFront() {
+ return mCanMoveToFrontCode != MOVE_TO_FRONT_ALLOWED;
+ }
+
+ private boolean avoidMoveToFrontPIOnlyCreatorAllows() {
+ return mCanMoveToFrontCode == MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS;
+ }
+
/**
* If the start result is success, ensure that the configuration of the started activity matches
* the current display. Otherwise clean up unassociated containers to avoid leakage.
@@ -1552,7 +1583,7 @@ class ActivityStarter {
currentTop, currentTop.getDisplayId(), false /* deferResume */);
}
- if (!mAvoidMoveToFront && mDoResume && mRootWindowContainer
+ if (!avoidMoveToFront() && mDoResume && mRootWindowContainer
.hasVisibleWindowAboveButDoesNotOwnNotificationShade(started.launchedFromUid)) {
// If the UID launching the activity has a visible window on top of the notification
// shade and it's launching an activity that's going to be at the front, we should move
@@ -1689,10 +1720,18 @@ class ActivityStarter {
}
// When running transient transition, the transient launch target should keep on top.
// So disallow the transient hide activity to move itself to front, e.g. trampoline.
- if (!mAvoidMoveToFront && (mService.mHomeProcess == null
+ if (!avoidMoveToFront() && (mService.mHomeProcess == null
|| mService.mHomeProcess.mUid != realCallingUid)
&& r.mTransitionController.isTransientHide(targetTask)) {
- mAvoidMoveToFront = true;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
+ }
+ // If the activity is started by sending a pending intent and only its creator has the
+ // privilege to allow BAL (its sender does not), avoid move it to the front. Only do
+ // this when it is not a new task and not already been marked as avoid move to front.
+ // Guarded by a flag: balDontBringExistingBackgroundTaskStackToFg
+ if (balDontBringExistingBackgroundTaskStackToFg() && !avoidMoveToFront()
+ && balVerdict.onlyCreatorAllows()) {
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS;
}
mPriorAboveTask = TaskDisplayArea.getRootTaskAbove(targetTask.getRootTask());
}
@@ -1746,15 +1785,19 @@ class ActivityStarter {
// After activity is attached to task, but before actual start
recordTransientLaunchIfNeeded(mLastStartActivityRecord);
- if (!mAvoidMoveToFront && mDoResume) {
- logOnlyCreatorAllowsBAL(balVerdict, realCallingUid, newTask);
- mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
- if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming()
- && !dreamStopping) {
- // Launching underneath dream activity (fullscreen, always-on-top). Run the launch-
- // -behind transition so the Activity gets created and starts in visible state.
- mLaunchTaskBehind = true;
- r.mLaunchTaskBehind = true;
+ if (mDoResume) {
+ if (!avoidMoveToFront()) {
+ mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
+ if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming()
+ && !dreamStopping) {
+ // Launching underneath dream activity (fullscreen, always-on-top). Run the
+ // launch--behind transition so the Activity gets created and starts
+ // in visible state.
+ mLaunchTaskBehind = true;
+ r.mLaunchTaskBehind = true;
+ }
+ } else {
+ logPIOnlyCreatorAllowsBAL();
}
}
@@ -1816,10 +1859,13 @@ class ActivityStarter {
// root-task to the will not update the focused root-task. If starting the new
// activity now allows the task root-task to be focusable, then ensure that we
// now update the focused root-task accordingly.
- if (!mAvoidMoveToFront && mTargetRootTask.isTopActivityFocusable()
+ if (mTargetRootTask.isTopActivityFocusable()
&& !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
- logOnlyCreatorAllowsBAL(balVerdict, realCallingUid, newTask);
- mTargetRootTask.moveToFront("startActivityInner");
+ if (!avoidMoveToFront()) {
+ mTargetRootTask.moveToFront("startActivityInner");
+ } else {
+ logPIOnlyCreatorAllowsBAL();
+ }
}
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
@@ -1847,25 +1893,24 @@ class ActivityStarter {
return START_SUCCESS;
}
- private void logOnlyCreatorAllowsBAL(BalVerdict balVerdict,
- int realCallingUid, boolean newTask) {
- // TODO (b/296478675) eventually, we will prevent such case from happening
- // and probably also log that a BAL is prevented by android V.
- if (!newTask && balVerdict.onlyCreatorAllows()) {
- String realCallingPackage =
- mService.mContext.getPackageManager().getNameForUid(realCallingUid);
- if (realCallingPackage == null) {
- realCallingPackage = "uid=" + realCallingUid;
- }
- Slog.wtf(TAG, "A background app is brought to the foreground due to a "
- + "PendingIntent. However, only the creator of the PendingIntent allows BAL, "
- + "while the sender does not allow BAL. realCallingPackage: "
- + realCallingPackage + "; callingPackage: " + mRequest.callingPackage
- + "; mTargetRootTask:" + mTargetRootTask + "; mIntent: " + mIntent
- + "; mTargetRootTask.getTopNonFinishingActivity: "
- + mTargetRootTask.getTopNonFinishingActivity()
- + "; mTargetRootTask.getRootActivity: " + mTargetRootTask.getRootActivity());
+ // TODO (b/316135632) Post V release, remove this log method.
+ private void logPIOnlyCreatorAllowsBAL() {
+ if (!avoidMoveToFrontPIOnlyCreatorAllows()) return;
+ String realCallingPackage =
+ mService.mContext.getPackageManager().getNameForUid(mRealCallingUid);
+ if (realCallingPackage == null) {
+ realCallingPackage = "uid=" + mRealCallingUid;
}
+ Slog.wtf(TAG, "Without Android 15 BAL hardening this activity would be moved to the "
+ + "foreground. The activity is started by a PendingIntent. However, only the "
+ + "creator of the PendingIntent allows BAL while the sender does not allow BAL. "
+ + "realCallingPackage: " + realCallingPackage
+ + "; callingPackage: " + mRequest.callingPackage
+ + "; mTargetRootTask:" + mTargetRootTask
+ + "; mIntent: " + mIntent
+ + "; mTargetRootTask.getTopNonFinishingActivity: "
+ + mTargetRootTask.getTopNonFinishingActivity()
+ + "; mTargetRootTask.getRootActivity: " + mTargetRootTask.getRootActivity());
}
private void recordTransientLaunchIfNeeded(ActivityRecord r) {
@@ -2064,7 +2109,7 @@ class ActivityStarter {
mRootWindowContainer.startPowerModeLaunchIfNeeded(false /* forceSend */,
targetTaskTop);
- setTargetRootTaskIfNeeded(targetTaskTop, balVerdict);
+ setTargetRootTaskIfNeeded(targetTaskTop);
// When there is a reused activity and the current result is a trampoline activity,
// set the reused activity as the result.
@@ -2080,13 +2125,12 @@ class ActivityStarter {
if (!mMovedToFront && mDoResume) {
ProtoLog.d(WM_DEBUG_TASKS, "Bring to front target: %s from %s", mTargetRootTask,
targetTaskTop);
- logOnlyCreatorAllowsBAL(balVerdict, mRealCallingUid, false);
mTargetRootTask.moveToFront("intentActivityFound");
}
+
resumeTargetRootTaskIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
-
complyActivityFlags(targetTask,
reusedTask != null ? reusedTask.getTopNonFinishingActivity() : null, intentGrants);
@@ -2109,7 +2153,6 @@ class ActivityStarter {
targetTaskTop.showStartingWindow(true /* taskSwitch */);
} else if (mDoResume) {
// Make sure the root task and its belonging display are moved to topmost.
- logOnlyCreatorAllowsBAL(balVerdict, mRealCallingUid, false);
mTargetRootTask.moveToFront("intentActivityFound");
}
// We didn't do anything... but it was needed (a.k.a., client don't use that intent!)
@@ -2344,7 +2387,7 @@ class ActivityStarter {
mIsTaskCleared = false;
mMovedToFront = false;
mNoAnimation = false;
- mAvoidMoveToFront = false;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_ALLOWED;
mFrozeTaskList = false;
mTransientLaunch = false;
mPriorAboveTask = null;
@@ -2456,12 +2499,12 @@ class ActivityStarter {
// The caller specifies that we'd like to be avoided to be moved to the
// front, so be it!
mDoResume = false;
- mAvoidMoveToFront = true;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
}
}
} else if (mOptions.getAvoidMoveToFront()) {
mDoResume = false;
- mAvoidMoveToFront = true;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
}
mTransientLaunch = mOptions.getTransientLaunch();
final KeyguardController kc = mSupervisor.getKeyguardController();
@@ -2471,7 +2514,7 @@ class ActivityStarter {
if (mTransientLaunch && mDisplayLockAndOccluded
&& mService.getTransitionController().isShellTransitionsEnabled()) {
mDoResume = false;
- mAvoidMoveToFront = true;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
}
mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
@@ -2528,7 +2571,7 @@ class ActivityStarter {
mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
if (mBalCode == BAL_BLOCK && !mService.isBackgroundActivityStartsEnabled()) {
- mAvoidMoveToFront = true;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
mDoResume = false;
}
}
@@ -2705,7 +2748,7 @@ class ActivityStarter {
* @param intentActivity Existing matching activity.
* @return {@link ActivityRecord} brought to front.
*/
- private void setTargetRootTaskIfNeeded(ActivityRecord intentActivity, BalVerdict balVerdict) {
+ private void setTargetRootTaskIfNeeded(ActivityRecord intentActivity) {
intentActivity.getTaskFragment().clearLastPausedActivity();
Task intentTask = intentActivity.getTask();
// The intent task might be reparented while in getOrCreateRootTask, caches the original
@@ -2742,7 +2785,7 @@ class ActivityStarter {
differentTopTask = true;
}
- if (differentTopTask && !mAvoidMoveToFront) {
+ if (differentTopTask && !avoidMoveToFront()) {
mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (mSourceRecord == null || inTopNonFinishingTask(mSourceRecord)) {
// We really do want to push this one into the user's face, right now.
@@ -2772,7 +2815,6 @@ class ActivityStarter {
// task on top there.
// Defer resuming the top activity while moving task to top, since the
// current task-top activity may not be the activity that should be resumed.
- logOnlyCreatorAllowsBAL(balVerdict, mRealCallingUid, false);
mTargetRootTask.moveTaskToFront(intentTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, DEFER_RESUME,
"bringingFoundTaskToFront");
@@ -2789,7 +2831,9 @@ class ActivityStarter {
mOptions = null;
}
}
-
+ if (differentTopTask) {
+ logPIOnlyCreatorAllowsBAL();
+ }
// Update the target's launch cookie and pending remote animation to those specified in the
// options if set.
if (mStartActivity.mLaunchCookie != null) {
@@ -2840,7 +2884,7 @@ class ActivityStarter {
}
private void setNewTask(Task taskToAffiliate) {
- final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
+ final boolean toTop = !mLaunchTaskBehind && !avoidMoveToFront();
final Task task = mTargetRootTask.reuseOrCreateTask(
mStartActivity.info, mIntent, mVoiceSession,
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 0d15fc932e68..2b841fdad9c0 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH;
import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
@@ -110,15 +111,6 @@ public class PhysicalDisplaySwitchTransitionLauncher {
return;
}
- final TransitionRequestInfo.DisplayChange displayChange =
- new TransitionRequestInfo.DisplayChange(displayId);
-
- final Rect startAbsBounds = new Rect(0, 0, oldDisplayWidth, oldDisplayHeight);
- displayChange.setStartAbsBounds(startAbsBounds);
- final Rect endAbsBounds = new Rect(0, 0, newDisplayWidth, newDisplayHeight);
- displayChange.setEndAbsBounds(endAbsBounds);
- displayChange.setPhysicalDisplayChanged(true);
-
mTransition = null;
if (mTransitionController.isCollecting()) {
@@ -128,10 +120,20 @@ public class PhysicalDisplaySwitchTransitionLauncher {
// Make sure that transition is not ready until we finish the remote display change
mTransition.setReady(mDisplayContent, false);
+ mTransition.addFlag(TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH);
ProtoLog.d(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
"Adding display switch to existing collecting transition");
} else {
+ final TransitionRequestInfo.DisplayChange displayChange =
+ new TransitionRequestInfo.DisplayChange(displayId);
+
+ final Rect startAbsBounds = new Rect(0, 0, oldDisplayWidth, oldDisplayHeight);
+ displayChange.setStartAbsBounds(startAbsBounds);
+ final Rect endAbsBounds = new Rect(0, 0, newDisplayWidth, newDisplayHeight);
+ displayChange.setEndAbsBounds(endAbsBounds);
+ displayChange.setPhysicalDisplayChanged(true);
+
mTransition = mTransitionController.requestTransitionIfNeeded(TRANSIT_CHANGE,
0 /* flags */,
mDisplayContent, mDisplayContent, null /* remoteTransition */,
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index d66b9b956071..2a0f1e2ede55 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -468,7 +468,6 @@ private:
borrowed_fd incomingFd, bool waitOnEof, std::vector<char>* buffer,
std::vector<IncFsDataBlock>* blocks) {
IncFsSize remaining = size;
- IncFsSize totalSize = 0;
IncFsBlockIndex blockIdx = 0;
while (remaining > 0) {
constexpr auto capacity = BUFFER_SIZE;
@@ -502,7 +501,6 @@ private:
buffer->resize(size + read);
remaining -= read;
- totalSize += read;
}
if (!buffer->empty() && !flashToIncFs(incfsFd, kind, true, &blockIdx, buffer, blocks)) {
return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e0a2f30b1831..a490013303e9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2469,7 +2469,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void migratePersonalAppSuspensionLocked(
int doUserId, int poUserId, ActiveAdmin poAdmin) {
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
- if (!pmi.isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, doUserId)) {
+ if (!pmi.isAdminSuspendingAnyPackages(doUserId)) {
Slogf.i(LOG_TAG, "DO is not suspending any apps.");
return;
}
@@ -2480,7 +2480,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
poAdmin.mSuspendPersonalApps = true;
} else {
Slogf.i(LOG_TAG, "PO isn't targeting R+, unsuspending personal apps.");
- pmi.unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, doUserId);
+ pmi.unsuspendAdminSuspendedPackages(doUserId);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 6570ce1cd500..506dbe8c48c4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -16,8 +16,6 @@
package com.android.server.devicepolicy;
-import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppGlobals;
@@ -287,7 +285,7 @@ final class PolicyEnforcerCallbacks {
suspendPersonalAppsInPackageManager(context, userId);
} else {
LocalServices.getService(PackageManagerInternal.class)
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, userId);
+ .unsuspendAdminSuspendedPackages(userId);
}
});
return true;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
index b396cf498a67..40d3d5ca9fd9 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -45,15 +45,19 @@ import android.annotation.NonNull;
import android.app.PropertyInvalidatedCache;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
+import android.content.pm.Flags;
import android.content.pm.PackageManager;
+import android.content.pm.SharedLibraryInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.os.BaseBundle;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -67,6 +71,7 @@ import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.LocalServices;
+import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.ArchiveState;
@@ -85,6 +90,7 @@ import com.google.common.truth.Truth;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -109,6 +115,9 @@ import java.util.concurrent.CountDownLatch;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PackageManagerSettingsTests {
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String PACKAGE_NAME_1 = "com.android.app1";
private static final String PACKAGE_NAME_2 = "com.android.app2";
private static final String PACKAGE_NAME_3 = "com.android.app3";
@@ -140,6 +149,7 @@ public class PackageManagerSettingsTests {
public void setup() {
// Disable binder caches in this process.
PropertyInvalidatedCache.disableForTestMode();
+
}
@Before
@@ -161,6 +171,107 @@ public class PackageManagerSettingsTests {
deleteFolder(InstrumentationRegistry.getContext().getFilesDir());
}
+ @Test
+ public void testApplicationInfoForUseSdkOptionalEnabled() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_SDK_LIB_INDEPENDENCE);
+
+ // Create basic information for SDK lib
+ final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+ ps1.setPkg(((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed())
+ .setUid(ps1.getAppId())
+ .setSystem(true)
+ .hideAsFinal());
+ ps1.setUsesSdkLibraries(new String[] { "com.example.sdk.one" });
+ ps1.setUsesSdkLibrariesVersionsMajor(new long[] { 12 });
+ ps1.setUsesSdkLibrariesOptional(new boolean[] {true});
+ ps1.addUsesLibraryInfo(new SharedLibraryInfo("path1",
+ "packageName1",
+ Collections.emptyList(),
+ "com.example.sdk.one",
+ 12 /*version*/,
+ SharedLibraryInfo.TYPE_SDK_PACKAGE,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ps1.addUsesLibraryInfo(new SharedLibraryInfo("path11",
+ "packageName11",
+ Collections.emptyList(),
+ "com.example.sdk.oneone",
+ 1212 /*version*/,
+ SharedLibraryInfo.TYPE_STATIC,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ApplicationInfo appInfo1 = PackageInfoUtils.generateApplicationInfo(ps1.getAndroidPackage(),
+ 0 /*flags*/, ps1.getUserStateOrDefault(0), 0 /*userId*/,
+ ps1);
+ assertThat(appInfo1, notNullValue());
+ assertThat(appInfo1.sharedLibraryInfos, notNullValue());
+ assertThat(appInfo1.optionalSharedLibraryInfos, notNullValue());
+ assertEquals(appInfo1.sharedLibraryInfos.get(0).getName(), "com.example.sdk.one");
+ assertEquals(appInfo1.optionalSharedLibraryInfos.get(0).getName(), "com.example.sdk.one");
+
+ final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
+ ps2.setPkg(((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_2).hideAsParsed())
+ .setUid(ps2.getAppId())
+ .setSystem(true)
+ .hideAsFinal());
+ ps2.setUsesSdkLibraries(new String[] { "com.example.sdk.two" });
+ ps2.setUsesSdkLibrariesVersionsMajor(new long[] { 34 });
+ ps2.setUsesSdkLibrariesOptional(new boolean[] {false});
+ ps2.addUsesLibraryInfo(new SharedLibraryInfo("path2",
+ "packageName2",
+ Collections.emptyList(),
+ "com.example.sdk.two",
+ 34 /*version*/,
+ SharedLibraryInfo.TYPE_SDK_PACKAGE,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ApplicationInfo appInfo2 = PackageInfoUtils.generateApplicationInfo(ps2.getAndroidPackage(),
+ 0 /*flags*/, ps2.getUserStateOrDefault(0), 0 /*userId*/,
+ ps2);
+ assertThat(appInfo2, notNullValue());
+ assertThat(appInfo2.sharedLibraryInfos, notNullValue());
+ assertThat(appInfo2.optionalSharedLibraryInfos, nullValue());
+ assertEquals(appInfo2.sharedLibraryInfos.get(0).getName(), "com.example.sdk.two");
+ }
+
+ @Test
+ public void testApplicationInfoForUseSdkOptionalDisabled() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_SDK_LIB_INDEPENDENCE);
+
+ // Create basic information for SDK lib
+ final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+ ps1.setPkg(((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed())
+ .setUid(ps1.getAppId())
+ .setSystem(true)
+ .hideAsFinal());
+ ps1.setUsesSdkLibraries(new String[] { "com.example.sdk.one" });
+ ps1.setUsesSdkLibrariesVersionsMajor(new long[] { 12 });
+ ps1.setUsesSdkLibrariesOptional(new boolean[] {true});
+ ps1.addUsesLibraryInfo(new SharedLibraryInfo("path1",
+ "packageName1",
+ Collections.emptyList(),
+ "com.example.sdk.one",
+ 12 /*version*/,
+ SharedLibraryInfo.TYPE_SDK_PACKAGE,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ApplicationInfo appInfo1 = PackageInfoUtils.generateApplicationInfo(ps1.getAndroidPackage(),
+ 0 /*flags*/, ps1.getUserStateOrDefault(0), 0 /*userId*/,
+ ps1);
+ assertThat(appInfo1, notNullValue());
+ assertThat(appInfo1.sharedLibraryInfos, notNullValue());
+ assertThat(appInfo1.optionalSharedLibraryInfos, nullValue());
+ assertEquals(appInfo1.sharedLibraryInfos.get(0).getName(), "com.example.sdk.one");
+ }
+
/** make sure our initialized KeySetManagerService metadata matches packages.xml */
@Test
public void testReadKeySetSettings() throws Exception {
@@ -315,7 +426,7 @@ public class PackageManagerSettingsTests {
PackageUserStateInternal packageUserState1 = ps1.readUserState(0);
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is("android"));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is(UserPackage.of(0, "android")));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getAppExtras(), is(nullValue()));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getDialogInfo(),
is(nullValue()));
@@ -327,7 +438,7 @@ public class PackageManagerSettingsTests {
packageUserState1 = ps1.readUserState(0);
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is("android"));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is(UserPackage.of(0, "android")));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getAppExtras(), is(nullValue()));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getDialogInfo(),
is(nullValue()));
@@ -362,7 +473,8 @@ public class PackageManagerSettingsTests {
watcher.verifyNoChangeReported("readUserState");
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is(PACKAGE_NAME_3));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0),
+ is(UserPackage.of(0, PACKAGE_NAME_3)));
final SuspendParams params = packageUserState1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("fetch user state");
assertThat(params, is(notNullValue()));
@@ -413,19 +525,24 @@ public class PackageManagerSettingsTests {
.setNeutralButtonAction(BUTTON_ACTION_UNSUSPEND)
.build();
- ps1.modifyUserState(0).putSuspendParams("suspendingPackage1",
+ UserPackage suspender1 = UserPackage.of(0, "suspendingPackage1");
+ UserPackage suspender2 = UserPackage.of(0, "suspendingPackage2");
+ UserPackage suspender3 = UserPackage.of(0, "suspendingPackage3");
+ UserPackage irrelevantSuspender = UserPackage.of(0, "irrelevant");
+
+ ps1.modifyUserState(0).putSuspendParams(suspender1,
new SuspendParams(dialogInfo1, appExtras1, launcherExtras1));
- ps1.modifyUserState(0).putSuspendParams("suspendingPackage2",
+ ps1.modifyUserState(0).putSuspendParams(suspender2,
new SuspendParams(dialogInfo2, appExtras2, launcherExtras2));
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
watcher.verifyChangeReported("put package 1");
- ps2.modifyUserState(0).putSuspendParams("suspendingPackage3",
+ ps2.modifyUserState(0).putSuspendParams(suspender3,
new SuspendParams(null, appExtras1, null));
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
watcher.verifyChangeReported("put package 2");
- ps3.modifyUserState(0).removeSuspension("irrelevant");
+ ps3.modifyUserState(0).removeSuspension(irrelevantSuspender);
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
watcher.verifyChangeReported("put package 3");
@@ -450,7 +567,7 @@ public class PackageManagerSettingsTests {
assertThat(readPus1.getSuspendParams().size(), is(2));
watcher.verifyNoChangeReported("read package param");
- assertThat(readPus1.getSuspendParams().keyAt(0), is("suspendingPackage1"));
+ assertThat(readPus1.getSuspendParams().keyAt(0), is(suspender1));
final SuspendParams params11 = readPus1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("read package param");
assertThat(params11, is(notNullValue()));
@@ -460,7 +577,7 @@ public class PackageManagerSettingsTests {
is(true));
watcher.verifyNoChangeReported("read package param");
- assertThat(readPus1.getSuspendParams().keyAt(1), is("suspendingPackage2"));
+ assertThat(readPus1.getSuspendParams().keyAt(1), is(suspender2));
final SuspendParams params12 = readPus1.getSuspendParams().valueAt(1);
assertThat(params12, is(notNullValue()));
assertThat(params12.getDialogInfo(), is(dialogInfo2));
@@ -473,7 +590,7 @@ public class PackageManagerSettingsTests {
.readUserState(0);
assertThat(readPus2.isSuspended(), is(true));
assertThat(readPus2.getSuspendParams().size(), is(1));
- assertThat(readPus2.getSuspendParams().keyAt(0), is("suspendingPackage3"));
+ assertThat(readPus2.getSuspendParams().keyAt(0), is(suspender3));
final SuspendParams params21 = readPus2.getSuspendParams().valueAt(0);
assertThat(params21, is(notNullValue()));
assertThat(params21.getDialogInfo(), is(nullValue()));
@@ -1024,7 +1141,8 @@ public class PackageManagerSettingsTests {
.setNeutralButtonText(0x11220003)
.setNeutralButtonAction(BUTTON_ACTION_MORE_DETAILS)
.build();
- origPkgSetting01.modifyUserState(0).putSuspendParams("suspendingPackage1",
+ origPkgSetting01.modifyUserState(0).putSuspendParams(
+ UserPackage.of(0, "suspendingPackage1"),
new SuspendParams(dialogInfo1, appExtras1, launcherExtras1));
origPkgSetting01.setPkg(mockAndroidPackage(origPkgSetting01));
final PackageSetting testPkgSetting01 = new PackageSetting(
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
index c0c70321c79b..978044045ab3 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertTrue;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.os.PersistableBundle;
import android.platform.test.annotations.Presubmit;
@@ -89,7 +90,7 @@ public class PackageUserStateTest {
assertThat(testUserState.equals(oldUserState), is(false));
oldUserState = new PackageUserStateImpl();
- oldUserState.putSuspendParams("suspendingPackage",
+ oldUserState.putSuspendParams(UserPackage.of(0, "suspendingPackage"),
new SuspendParams(null, new PersistableBundle(), null));
assertThat(testUserState.equals(oldUserState), is(false));
@@ -220,6 +221,8 @@ public class PackageUserStateTest {
final PersistableBundle launcherExtras2 = createPersistableBundle(null, 0, "name",
"launcherExtras2", null, 0);
+ final int suspendingUser1 = 0;
+ final int suspendingUser2 = 10;
final String suspendingPackage1 = "package1";
final String suspendingPackage2 = "package2";
@@ -230,12 +233,12 @@ public class PackageUserStateTest {
.setMessage("dialogMessage2")
.build();
- final ArrayMap<String, SuspendParams> paramsMap1 = new ArrayMap<>();
- paramsMap1.put(suspendingPackage1, createSuspendParams(dialogInfo1, appExtras1,
- launcherExtras1));
- final ArrayMap<String, SuspendParams> paramsMap2 = new ArrayMap<>();
- paramsMap2.put(suspendingPackage2, createSuspendParams(dialogInfo2,
- appExtras2, launcherExtras2));
+ final ArrayMap<UserPackage, SuspendParams> paramsMap1 = new ArrayMap<>();
+ paramsMap1.put(UserPackage.of(suspendingUser1, suspendingPackage1),
+ createSuspendParams(dialogInfo1, appExtras1, launcherExtras1));
+ final ArrayMap<UserPackage, SuspendParams> paramsMap2 = new ArrayMap<>();
+ paramsMap2.put(UserPackage.of(suspendingUser2, suspendingPackage2),
+ createSuspendParams(dialogInfo2, appExtras2, launcherExtras2));
final PackageUserStateImpl testUserState1 = new PackageUserStateImpl();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt
new file mode 100644
index 000000000000..ebb4f1889cd6
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.display.mode
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.provider.Settings
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SmallTest
+import com.android.internal.util.test.FakeSettingsProvider
+import com.android.server.display.feature.DisplayManagerFlags
+import com.android.server.testutils.TestHandler
+import com.google.common.truth.Truth.assertThat
+import com.google.testing.junit.testparameterinjector.TestParameter
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(TestParameterInjector::class)
+class SettingsObserverTest {
+
+ @get:Rule
+ val mockitoRule = MockitoJUnit.rule()
+
+ @get:Rule
+ val settingsProviderRule = FakeSettingsProvider.rule()
+
+ private lateinit var spyContext: Context
+ private val mockInjector = mock<DisplayModeDirector.Injector>()
+ private val mockFlags = mock<DisplayManagerFlags>()
+
+ private val testHandler = TestHandler(null)
+
+ @Before
+ fun setUp() {
+ spyContext = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
+ }
+
+ @Test
+ fun testLowPowerMode(@TestParameter testCase: SettingsObserverTestCase) {
+ whenever(mockFlags.isVsyncLowPowerVoteEnabled).thenReturn(testCase.vsyncLowPowerVoteEnabled)
+ whenever(spyContext.contentResolver)
+ .thenReturn(settingsProviderRule.mockContentResolver(null))
+ val lowPowerModeSetting = if (testCase.lowPowerModeEnabled) 1 else 0
+ Settings.Global.putInt(
+ spyContext.contentResolver, Settings.Global.LOW_POWER_MODE, lowPowerModeSetting)
+
+ val displayModeDirector = DisplayModeDirector(
+ spyContext, testHandler, mockInjector, mockFlags)
+ val settingsObserver = displayModeDirector.SettingsObserver(
+ spyContext, testHandler, testCase.dvrrSupported, mockFlags)
+
+ settingsObserver.onChange(
+ false, Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE), 1)
+
+ assertThat(displayModeDirector.getVote(VotesStorage.GLOBAL_ID,
+ Vote.PRIORITY_LOW_POWER_MODE)).isEqualTo(testCase.expectedVote)
+ }
+
+ enum class SettingsObserverTestCase(
+ val dvrrSupported: Boolean,
+ val vsyncLowPowerVoteEnabled: Boolean,
+ val lowPowerModeEnabled: Boolean,
+ internal val expectedVote: Vote?
+ ) {
+ ALL_ENABLED(true, true, true,
+ SupportedModesVote(listOf(
+ SupportedModesVote.SupportedMode(60f, 240f),
+ SupportedModesVote.SupportedMode(60f, 60f)
+ ))),
+ LOW_POWER_OFF(true, true, false, null),
+ DVRR_NOT_SUPPORTED_LOW_POWER_ON(false, true, true,
+ RefreshRateVote.RenderVote(0f, 60f)),
+ DVRR_NOT_SUPPORTED_LOW_POWER_OFF(false, true, false, null),
+ VSYNC_VOTE_DISABLED_SUPPORTED_LOW_POWER_ON(true, false, true,
+ RefreshRateVote.RenderVote(0f, 60f)),
+ VSYNC_VOTE_DISABLED_LOW_POWER_OFF(true, false, false, null),
+ }
+} \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
index ae53e707a7cc..7444403f88c8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -19,6 +19,7 @@ package com.android.server.pm
import android.app.AppOpsManager
import android.content.Intent
import android.content.pm.SuspendDialogInfo
+import android.content.pm.UserPackage
import android.os.Binder
import android.os.PersistableBundle
import com.android.server.testutils.any
@@ -41,12 +42,18 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
.thenReturn(AppOpsManager.MODE_DEFAULT)
}
+ companion object {
+ val doUserPackage = UserPackage.of(TEST_USER_ID, DEVICE_OWNER_PACKAGE)
+ val platformUserPackage = UserPackage.of(TEST_USER_ID, PLATFORM_PACKAGE_NAME)
+ val testUserPackage1 = UserPackage.of(TEST_USER_ID, TEST_PACKAGE_1)
+ }
+
@Test
fun setPackagesSuspended() {
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
@@ -63,14 +70,14 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_emptyPackageName() {
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
null /* packageNames */, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).isNull()
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOfNulls(0), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).isEmpty()
@@ -80,7 +87,8 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_callerIsNotAllowed() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID,
+ null /* launcherExtras */, null /* dialogInfo */,
+ testUserPackage1, TEST_USER_ID,
Binder.getCallingUid(), false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -91,7 +99,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_callerSuspendItself() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(DEVICE_OWNER_PACKAGE), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -102,7 +110,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_nonexistentPackage() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(NONEXISTENT_PACKAGE), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -115,7 +123,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE)
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
knownPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)!!
assertThat(failedNames.size).isEqualTo(knownPackages.size)
@@ -129,14 +137,14 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
Mockito.clearInvocations(broadcastHelper)
assertThat(failedNames).isEmpty()
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, false /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
@@ -184,7 +192,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
appExtras.putString(TEST_PACKAGE_1, TEST_PACKAGE_1)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, appExtras, null /* launcherExtras */,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -202,22 +210,22 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, appExtras, null /* launcherExtras */,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
Mockito.clearInvocations(broadcastHelper)
assertThat(failedNames).isEmpty()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
assertThat(SuspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNotNull()
assertThat(SuspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNotNull()
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE },
+ targetPackages, { suspender -> suspender.packageName == DEVICE_OWNER_PACKAGE },
TEST_USER_ID)
testHandler.flush()
@@ -243,7 +251,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -258,7 +266,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun isPackageSuspended() {
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -273,13 +281,13 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
}
@Test
@@ -290,57 +298,57 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
// Suspend.
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
assertThat(failedNames).isEmpty()
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
// Suspend by system.
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, PLATFORM_PACKAGE_NAME, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, platformUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
assertThat(failedNames).isEmpty()
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(PLATFORM_PACKAGE_NAME)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(platformUserPackage)
// QAS by package1.
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, testUserPackage1, TEST_USER_ID, deviceOwnerUid,
true /* quarantined */)
assertThat(failedNames).isEmpty()
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(TEST_PACKAGE_1)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(testUserPackage1)
// Un-QAS by package1.
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == TEST_PACKAGE_1 },
+ targetPackages, { suspendingPackage -> suspendingPackage == testUserPackage1 },
TEST_USER_ID)
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(PLATFORM_PACKAGE_NAME)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(platformUserPackage)
// Un-suspend by system.
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == PLATFORM_PACKAGE_NAME },
+ targetPackages, { suspender -> suspender.packageName == PLATFORM_PACKAGE_NAME },
TEST_USER_ID)
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
// Unsuspend.
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE },
+ targetPackages, { suspendingPackage -> suspendingPackage == doUserPackage },
TEST_USER_ID)
testHandler.flush()
@@ -354,13 +362,13 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
.setTitle(TEST_PACKAGE_1).build()
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, dialogInfo, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
+ null /* launcherExtras */, dialogInfo, doUserPackage, TEST_USER_ID,
deviceOwnerUid, false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
val result = suspendPackageHelper.getSuspendedDialogInfo(pms.snapshotComputer(),
- TEST_PACKAGE_1, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)!!
+ TEST_PACKAGE_1, doUserPackage, TEST_USER_ID, deviceOwnerUid)!!
assertThat(result.title).isEqualTo(TEST_PACKAGE_1)
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index a78f2dcf2ab2..3b5cae328b3c 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -23,6 +23,8 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
@@ -41,6 +43,7 @@ import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.Flags;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -108,6 +111,7 @@ public class AuthServiceTest {
@Mock
IFaceService mFaceService;
@Mock
+
AppOpsManager mAppOpsManager;
@Mock
private VirtualDeviceManagerInternal mVdmInternal;
@@ -404,6 +408,23 @@ public class AuthServiceTest {
eq(TEST_OP_PACKAGE_NAME));
}
+ @Test
+ public void testRegisterAuthenticationStateListener_callsFingerprintService()
+ throws Exception {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
+ setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */);
+
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final AuthenticationStateListener listener = mock(AuthenticationStateListener.class);
+
+ mAuthService.mImpl.registerAuthenticationStateListener(listener);
+
+ waitForIdle();
+ verify(mFingerprintService).registerAuthenticationStateListener(
+ eq(listener));
+ }
@Test
public void testRegisterKeyguardCallback_callsBiometricServiceRegisterKeyguardCallback()
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
index 5012335b533f..94cb860ae710 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -23,10 +25,11 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
import androidx.test.filters.SmallTest;
@@ -40,6 +43,7 @@ import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
+@RequiresFlagsDisabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
@Presubmit
@SmallTest
public class SensorOverlaysTest {
@@ -97,7 +101,7 @@ public class SensorOverlaysTest {
private void testShow(IUdfpsOverlayController udfps, ISidefpsController sidefps)
throws Exception {
final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps);
- final int reason = BiometricOverlayConstants.REASON_UNKNOWN;
+ final int reason = BiometricRequestConstants.REASON_UNKNOWN;
sensorOverlays.show(SENSOR_ID, reason, mAcquisitionClient);
if (udfps != null) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index 79a528c59f49..c24227fcd1f7 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -18,6 +18,8 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -56,6 +58,7 @@ import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
@@ -68,6 +71,7 @@ import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -91,6 +95,8 @@ import java.util.function.Consumer;
@SmallTest
public class FingerprintAuthenticationClientTest {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final int SENSOR_ID = 4;
private static final int USER_ID = 8;
private static final long OP_ID = 7;
@@ -128,6 +134,8 @@ public class FingerprintAuthenticationClientTest {
@Mock
private ISidefpsController mSideFpsController;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private FingerprintSensorPropertiesInternal mSensorProps;
@Mock
private ClientMonitorCallback mCallback;
@@ -384,6 +392,7 @@ public class FingerprintAuthenticationClientTest {
private void showHideOverlay(Consumer<FingerprintAuthenticationClient> block)
throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
@@ -398,6 +407,49 @@ public class FingerprintAuthenticationClientTest {
}
@Test
+ public void showHideOverlay_cancel_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.cancel());
+ }
+
+ @Test
+ public void showHideOverlay_stop_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.stopHalOperation());
+ }
+
+ @Test
+ public void showHideOverlay_error_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onError(0, 0));
+ verify(mCallback).onClientFinished(any(), eq(false));
+ }
+
+ @Test
+ public void showHideOverlay_lockout_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onLockoutTimed(5000));
+ }
+
+ @Test
+ public void showHideOverlay_lockoutPerm_sidefpsControllerRemovalRefactor()
+ throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onLockoutPermanent());
+ }
+
+ private void showHideOverlay_sidefpsControllerRemovalRefactor(
+ Consumer<FingerprintAuthenticationClient> block) throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
+ final FingerprintAuthenticationClient client = createClient();
+
+ client.start(mCallback);
+
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
+ verify(mAuthenticationStateListeners).onAuthenticationStarted(anyInt());
+
+ block.accept(client);
+
+ verify(mUdfpsOverlayController).hideUdfpsOverlay(anyInt());
+ verify(mAuthenticationStateListeners).onAuthenticationStopped();
+ }
+
+ @Test
public void cancelsAuthWhenNotInForeground() throws Exception {
final ActivityManager.RunningTaskInfo topTask = new ActivityManager.RunningTaskInfo();
topTask.topActivity = new ComponentName("other", "thing");
@@ -502,7 +554,8 @@ public class FingerprintAuthenticationClientTest {
mBiometricLogger, mBiometricContext,
true /* isStrongBiometric */,
null /* taskStackListener */,
- mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication,
+ mUdfpsOverlayController, mSideFpsController, mAuthenticationStateListeners,
+ allowBackgroundAuthentication,
mSensorProps,
new Handler(mLooper.getLooper()), 0 /* biometricStrength */, mClock,
lockoutTracker) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index c7eb1db3e74b..e7d4a2e463f7 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -38,6 +40,7 @@ import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
@@ -48,6 +51,7 @@ import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -68,6 +72,8 @@ import java.util.function.Consumer;
@SmallTest
public class FingerprintEnrollClientTest {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final byte[] HAT = new byte[69];
private static final int USER_ID = 8;
private static final long REQUEST_ID = 9;
@@ -98,6 +104,8 @@ public class FingerprintEnrollClientTest {
@Mock
private ISidefpsController mSideFpsController;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private FingerprintSensorPropertiesInternal mSensorProps;
@Mock
private ClientMonitorCallback mCallback;
@@ -271,6 +279,7 @@ public class FingerprintEnrollClientTest {
private void showHideOverlay(Consumer<FingerprintEnrollClient> block)
throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
final FingerprintEnrollClient client = createClient();
client.start(mCallback);
@@ -284,6 +293,44 @@ public class FingerprintEnrollClientTest {
verify(mSideFpsController).hide(anyInt());
}
+ @Test
+ public void showHideOverlay_cancel_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.cancel());
+ }
+
+ @Test
+ public void showHideOverlay_stop_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.stopHalOperation());
+ }
+
+ @Test
+ public void showHideOverlay_error_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onError(0, 0));
+ verify(mCallback).onClientFinished(any(), eq(false));
+ }
+
+ @Test
+ public void showHideOverlay_result_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(
+ c -> c.onEnrollResult(new Fingerprint("", 1, 1), 0));
+ }
+
+ private void showHideOverlay_sidefpsControllerRemovalRefactor(
+ Consumer<FingerprintEnrollClient> block) throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
+ final FingerprintEnrollClient client = createClient();
+
+ client.start(mCallback);
+
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
+ verify(mAuthenticationStateListeners).onAuthenticationStarted(anyInt());
+
+ block.accept(client);
+
+ verify(mUdfpsOverlayController).hideUdfpsOverlay(anyInt());
+ verify(mAuthenticationStateListeners).onAuthenticationStopped();
+ }
+
private FingerprintEnrollClient createClient() throws RemoteException {
return createClient(500);
}
@@ -296,6 +343,7 @@ public class FingerprintEnrollClientTest {
mClientMonitorCallbackConverter, 0 /* userId */,
HAT, "owner", mBiometricUtils, 8 /* sensorId */,
mBiometricLogger, mBiometricContext, mSensorProps, mUdfpsOverlayController,
- mSideFpsController, 6 /* maxTemplatesPerUser */, FingerprintManager.ENROLL_ENROLL);
+ mSideFpsController, mAuthenticationStateListeners, 6 /* maxTemplatesPerUser */,
+ FingerprintManager.ENROLL_ENROLL);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index 8f6efffcbff8..4cfb83fa1c69 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -43,6 +43,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -74,6 +75,8 @@ public class FingerprintProviderTest {
@Mock
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private BiometricStateCallback mBiometricStateCallback;
@Mock
private BiometricContext mBiometricContext;
@@ -110,8 +113,9 @@ public class FingerprintProviderTest {
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
mFingerprintProvider = new FingerprintProvider(mContext,
- mBiometricStateCallback, mSensorProps, TAG, mLockoutResetDispatcher,
- mGestureAvailabilityDispatcher, mBiometricContext, mDaemon);
+ mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG,
+ mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext,
+ mDaemon);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
index b32b89aaefb0..0d3f1921c947 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
@@ -40,6 +40,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
@@ -70,6 +71,8 @@ public class Fingerprint21Test {
@Mock
private BiometricScheduler mScheduler;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private BiometricStateCallback mBiometricStateCallback;
@Mock
private BiometricContext mBiometricContext;
@@ -102,9 +105,10 @@ public class Fingerprint21Test {
componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN,
resetLockoutRequiresHardwareAuthToken);
- mFingerprint21 = new TestableFingerprint21(mContext, mBiometricStateCallback, sensorProps,
- mScheduler, new Handler(Looper.getMainLooper()), mLockoutResetDispatcher,
- mHalResultController, mBiometricContext);
+ mFingerprint21 = new TestableFingerprint21(mContext, mBiometricStateCallback,
+ mAuthenticationStateListeners, sensorProps, mScheduler,
+ new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, mHalResultController,
+ mBiometricContext);
}
@Test
@@ -126,13 +130,14 @@ public class Fingerprint21Test {
TestableFingerprint21(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller,
@NonNull BiometricContext biometricContext) {
- super(context, biometricStateCallback, sensorProps, scheduler, handler,
- lockoutResetDispatcher, controller, biometricContext);
+ super(context, biometricStateCallback, authenticationStateListeners, sensorProps,
+ scheduler, handler, lockoutResetDispatcher, controller, biometricContext);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index 943a9c4759c4..1dd64ffa5dde 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -18,7 +18,6 @@ package com.android.server.devicepolicy;
import static android.os.UserHandle.USER_SYSTEM;
import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile;
-import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -222,21 +221,21 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);
// Pretend some packages are suspended.
- when(getServices().packageManagerInternal.isSuspendingAnyPackages(
- PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
+ when(getServices().packageManagerInternal.isAdminSuspendingAnyPackages(
+ USER_SYSTEM)).thenReturn(true);
final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
verify(getServices().packageManagerInternal, never())
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(USER_SYSTEM);
sendBroadcastWithUser(dpms, Intent.ACTION_USER_STARTED, USER_SYSTEM);
// Verify that actual package suspension state is not modified after user start
verify(getServices().packageManagerInternal, never())
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(USER_SYSTEM);
verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
- any(), anyBoolean(), any(), any(), any(), anyInt(), any(), anyInt());
+ any(), anyBoolean(), any(), any(), any(), anyInt(), any(), anyInt(), anyInt());
final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
@@ -255,14 +254,14 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.Q);
// Pretend some packages are suspended.
- when(getServices().packageManagerInternal.isSuspendingAnyPackages(
- PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
+ when(getServices().packageManagerInternal.isAdminSuspendingAnyPackages(
+ USER_SYSTEM)).thenReturn(true);
final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
// Verify that apps get unsuspended.
verify(getServices().packageManagerInternal)
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(USER_SYSTEM);
final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index f4dac2c10d0f..24704034ae0c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -63,7 +63,6 @@ import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION;
import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE;
-import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.testutils.TestUtils.assertExpectException;
import static com.google.common.truth.Truth.assertThat;
@@ -5080,7 +5079,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().iwindowManager).refreshScreenCaptureDisabled();
// Unsuspend personal apps
verify(getServices().packageManagerInternal)
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, UserHandle.USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(UserHandle.USER_SYSTEM);
verify(getServices().subscriptionManager).setSubscriptionUserHandle(0, null);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
FLAG_ENABLE_WORK_PROFILE_TELEPHONY, "false", false);
@@ -7535,7 +7534,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
.cancel(eq(SystemMessageProto.SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED));
// Verify that the apps are NOT unsuspeded.
verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
- any(), eq(false), any(), any(), any(), anyInt(), any(), anyInt());
+ any(), eq(false), any(), any(), any(), anyInt(), any(), anyInt(), anyInt());
// Verify that DPC is invoked to check policy compliance.
verify(mContext.spiedContext).startActivityAsUser(
MockUtils.checkIntentAction(ACTION_CHECK_POLICY_COMPLIANCE),
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java b/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
index fe37f4241d8e..b3d25f2eef25 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
@@ -47,6 +47,10 @@ import java.util.Map;
@Presubmit
@RunWith(AndroidJUnit4.class)
public final class OverrideRequestControllerTest {
+
+ private static final DeviceState TEST_DEVICE_STATE_ZERO = new DeviceState(0, "TEST_STATE", 0);
+ private static final DeviceState TEST_DEVICE_STATE_ONE = new DeviceState(1, "TEST_STATE", 0);
+
private TestStatusChangeListener mStatusListener;
private OverrideRequestController mController;
@@ -59,7 +63,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addRequest() {
OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(request));
mController.addRequest(request);
@@ -69,14 +73,14 @@ public final class OverrideRequestControllerTest {
@Test
public void addRequest_cancelExistingRequestThroughNewRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(firstRequest));
mController.addRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(secondRequest));
mController.addRequest(secondRequest);
@@ -87,7 +91,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addRequest_cancelActiveRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
mController.addRequest(firstRequest);
@@ -101,7 +105,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addBaseStateRequest() {
OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(request));
mController.addBaseStateRequest(request);
@@ -111,14 +115,14 @@ public final class OverrideRequestControllerTest {
@Test
public void addBaseStateRequest_cancelExistingBaseStateRequestThroughNewRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(firstRequest));
mController.addBaseStateRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(secondRequest));
mController.addBaseStateRequest(secondRequest);
@@ -129,7 +133,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addBaseStateRequest_cancelActiveBaseStateRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addBaseStateRequest(firstRequest);
@@ -143,13 +147,13 @@ public final class OverrideRequestControllerTest {
@Test
public void handleBaseStateChanged() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */,
+ TEST_DEVICE_STATE_ZERO,
DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES /* flags */,
OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 0 /* requestedState */,
+ TEST_DEVICE_STATE_ZERO,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
@@ -169,11 +173,11 @@ public final class OverrideRequestControllerTest {
@Test
public void handleProcessDied() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 1 /* requestedState */,
+ TEST_DEVICE_STATE_ONE,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
@@ -192,11 +196,11 @@ public final class OverrideRequestControllerTest {
mController.setStickyRequestsAllowed(true);
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
@@ -215,11 +219,11 @@ public final class OverrideRequestControllerTest {
@Test
public void handleNewSupportedStates() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 1 /* requestedState */,
+ TEST_DEVICE_STATE_ONE,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
@@ -242,7 +246,7 @@ public final class OverrideRequestControllerTest {
@Test
public void cancelOverrideRequestsTest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
mController.addRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
index fb7857494515..0d25faf2bcf1 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
@@ -60,6 +60,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.inputmethod.StartInputFlags;
+import com.google.common.truth.Truth;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -1336,6 +1338,54 @@ public class InputMethodUtilsTest {
}
}
+ private static void verifySplitEnabledImeStr(@NonNull String enabledImeStr,
+ @NonNull String... expected) {
+ final ArrayList<String> actual = new ArrayList<>();
+ InputMethodUtils.splitEnabledImeStr(enabledImeStr, actual::add);
+ if (expected.length == 0) {
+ Truth.assertThat(actual).isEmpty();
+ } else {
+ Truth.assertThat(actual).containsExactlyElementsIn(expected);
+ }
+ }
+
+ @Test
+ public void testSplitEnabledImeStr() {
+ verifySplitEnabledImeStr("");
+ verifySplitEnabledImeStr("com.android/.ime1", "com.android/.ime1");
+ verifySplitEnabledImeStr("com.android/.ime1;1;2;3", "com.android/.ime1");
+ verifySplitEnabledImeStr("com.android/.ime1;1;2;3:com.android/.ime2",
+ "com.android/.ime1", "com.android/.ime2");
+ verifySplitEnabledImeStr("com.android/.ime1:com.android/.ime2",
+ "com.android/.ime1", "com.android/.ime2");
+ verifySplitEnabledImeStr("com.android/.ime1:com.android/.ime2:com.android/.ime3",
+ "com.android/.ime1", "com.android/.ime2", "com.android/.ime3");
+ verifySplitEnabledImeStr("com.android/.ime1;1:com.android/.ime2;1:com.android/.ime3;1",
+ "com.android/.ime1", "com.android/.ime2", "com.android/.ime3");
+ }
+
+ @Test
+ public void testConcatEnabledImeIds() {
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds("")).isEmpty();
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds("", "com.android/.ime1"))
+ .isEqualTo("com.android/.ime1");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1", "com.android/.ime1"))
+ .isEqualTo("com.android/.ime1");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1", "com.android/.ime2"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1", "com.android/.ime2", "com.android/.ime3"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2:com.android/.ime3");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1:com.android/.ime2", "com.android/.ime1"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1:com.android/.ime2", "com.android/.ime3"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2:com.android/.ime3");
+ }
+
@Test
public void updateEnabledImeStringTest() {
// No change cases
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 14b551ae0b22..776189eeb7c3 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -219,6 +219,7 @@ import android.provider.MediaStore;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.ConversationChannelWrapper;
+import android.service.notification.DeviceEffectsApplier;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
@@ -635,6 +636,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
private void initNMS() throws Exception {
+ initNMS(SystemService.PHASE_BOOT_COMPLETED);
+ }
+
+ private void initNMS(int upToBootPhase) throws Exception {
mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
mNotificationInstanceIdSequence);
@@ -662,13 +667,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager,
mPowerManager, mPostNotificationTrackerFactory);
+
// Return first true for RoleObserver main-thread check
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
- mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
+
+ if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
+ }
+
Mockito.reset(mHistoryManager);
verify(mHistoryManager, never()).onBootPhaseAppsCanStart();
- mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
- verify(mHistoryManager).onBootPhaseAppsCanStart();
+
+ if (upToBootPhase >= SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
+ verify(mHistoryManager).onBootPhaseAppsCanStart();
+ }
// TODO b/291907312: remove feature flag
if (Flags.refactorAttentionHelper()) {
@@ -914,7 +927,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mTestNotificationChannel.setAllowBubbles(channelEnabled);
}
- private void setUpPrefsForHistory(int uid, boolean globalEnabled) {
+ private void setUpPrefsForHistory(int uid, boolean globalEnabled) throws Exception {
+ initNMS(SystemService.PHASE_ACTIVITY_MANAGER_READY);
+
// Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, uid);
@@ -10090,7 +10105,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testHandleOnPackageRemoved_ClearsHistory() throws RemoteException {
+ public void testHandleOnPackageRemoved_ClearsHistory() throws Exception {
// Enables Notification History setting
setUpPrefsForHistory(mUid, true /* =enabled */);
@@ -13209,6 +13224,34 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void setDeviceEffectsApplier_succeeds() throws Exception {
+ initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
+ // No exception!
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void setDeviceEffectsApplier_tooLate_throws() throws Exception {
+ initNMS(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+
+ assertThrows(IllegalStateException.class, () ->
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void setDeviceEffectsApplier_calledTwice_throws() throws Exception {
+ initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
+ assertThrows(IllegalStateException.class, () ->
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
+ }
+
+ @Test
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index 526201f9c1c6..670f9f697a5c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -49,6 +49,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -195,7 +196,7 @@ public class ActivityStartInterceptorTest {
mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
- .thenReturn(PLATFORM_PACKAGE_NAME);
+ .thenReturn(UserPackage.of(TEST_USER_ID, PLATFORM_PACKAGE_NAME));
// THEN calling intercept returns true
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
@@ -227,9 +228,10 @@ public class ActivityStartInterceptorTest {
.setMessage("Test Message")
.setIcon(0x11110001)
.build();
+ UserPackage suspender = UserPackage.of(TEST_USER_ID, suspendingPackage);
when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
- .thenReturn(suspendingPackage);
- when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspendingPackage,
+ .thenReturn(suspender);
+ when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspender,
TEST_USER_ID)).thenReturn(dialogInfo);
return dialogInfo;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 98055fa6f0d5..8a9c05d07b26 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -117,6 +117,7 @@ import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.DeviceConfigStateHelper;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.am.PendingIntentRecord;
+import com.android.server.pm.PackageArchiver;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
@@ -421,6 +422,7 @@ public class ActivityStarterTests extends WindowTestsBase {
doNothing().when(mMockPackageManager).grantImplicitAccess(
anyInt(), any(), anyInt(), anyInt(), anyBoolean());
doNothing().when(mMockPackageManager).notifyPackageUse(anyString(), anyInt());
+ doReturn(mock(PackageArchiver.class)).when(mMockPackageManager).getPackageArchiver();
final Intent intent = new Intent();
intent.addFlags(launchFlags);
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java
index eac4d1682aa9..cc768bc00250 100644
--- a/telephony/java/android/telephony/CarrierRestrictionRules.java
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -16,12 +16,16 @@
package android.telephony;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.carrier.CarrierIdentifier;
+import android.telephony.TelephonyManager.CarrierRestrictionStatus;
+
+import com.android.internal.telephony.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -104,7 +108,7 @@ public final class CarrierRestrictionRules implements Parcelable {
private int mCarrierRestrictionDefault;
@MultiSimPolicy
private int mMultiSimPolicy;
- @TelephonyManager.CarrierRestrictionStatus
+ @CarrierRestrictionStatus
private int mCarrierRestrictionStatus;
private CarrierRestrictionRules() {
@@ -293,8 +297,22 @@ public final class CarrierRestrictionRules implements Parcelable {
return true;
}
- /** @hide */
- public int getCarrierRestrictionStatus() {
+ /**
+ * Get the carrier restriction status of the device.
+ * The return value of the API is as follows.
+ * <ul>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER}
+ * if the caller and the device locked by the network are same</li>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_RESTRICTED} if the
+ * caller and the device locked by the network are different</li>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_NOT_RESTRICTED} if the
+ * device is not locked</li>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_UNKNOWN} if the device
+ * locking state is unavailable or radio does not supports the feature</li>
+ * </ul>
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_RESTRICTION_STATUS)
+ public @CarrierRestrictionStatus int getCarrierRestrictionStatus() {
return mCarrierRestrictionStatus;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f206987ddbf6..5520cf6f50ba 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -18025,16 +18025,16 @@ public class TelephonyManager {
@FlaggedApi(Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY)
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
- public void enableCellularIdentifierDisclosureNotifications(boolean enable) {
+ public void setEnableCellularIdentifierDisclosureNotifications(boolean enable) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- telephony.enableCellularIdentifierDisclosureNotifications(enable);
+ telephony.setEnableCellularIdentifierDisclosureNotifications(enable);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- Rlog.e(TAG, "enableCellularIdentifierDisclosureNotifications RemoteException", ex);
+ Rlog.e(TAG, "setEnableCellularIdentifierDisclosureNotifications RemoteException", ex);
ex.rethrowFromSystemServer();
}
}
@@ -18051,16 +18051,16 @@ public class TelephonyManager {
@FlaggedApi(Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY)
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@SystemApi
- public boolean isCellularIdentifierDisclosureNotificationEnabled() {
+ public boolean isCellularIdentifierDisclosureNotificationsEnabled() {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.isCellularIdentifierDisclosureNotificationEnabled();
+ return telephony.isCellularIdentifierDisclosureNotificationsEnabled();
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- Rlog.e(TAG, "isCellularIdentifierDisclosureNotificationEnabled RemoteException", ex);
+ Rlog.e(TAG, "isCellularIdentifierDisclosureNotificationsEnabled RemoteException", ex);
ex.rethrowFromSystemServer();
}
return false;
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 3e8787281f85..8679bd4baf2e 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1866,7 +1866,7 @@ public class ApnSetting implements Parcelable {
private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
private int mSkip464Xlat = Carriers.SKIP_464XLAT_DEFAULT;
private boolean mAlwaysOn;
- private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR;
+ private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR | INFRASTRUCTURE_SATELLITE;
private boolean mEsimBootstrapProvisioning;
/**
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 397fb2d6db96..37752d0cecd8 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3182,7 +3182,7 @@ interface ITelephony {
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.MODIFY_PHONE_STATE)")
- void enableCellularIdentifierDisclosureNotifications(boolean enable);
+ void setEnableCellularIdentifierDisclosureNotifications(boolean enable);
/**
* Get whether or not cellular identifier disclosure notifications are enabled.
@@ -3196,5 +3196,5 @@ interface ITelephony {
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)")
- boolean isCellularIdentifierDisclosureNotificationEnabled();
+ boolean isCellularIdentifierDisclosureNotificationsEnabled();
}
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index 12a57d52491a..c8cac8fa2c82 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -25,6 +25,7 @@ import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
@@ -142,7 +143,7 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) :
}
/** During the transition Secondary Activity shrinks to the bottom right corner. */
- @Presubmit
+ @FlakyTest(bugId = 315605409)
@Test
fun secondaryLayerShrinks() {
flicker.assertLayers {