summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java5
-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.txt10
-rw-r--r--core/api/module-lib-current.txt1
-rw-r--r--core/api/system-current.txt18
-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/ActivityThread.java2
-rw-r--r--core/java/android/app/ApplicationPackageManager.java2
-rw-r--r--core/java/android/app/ApplicationStartInfo.java11
-rw-r--r--core/java/android/app/AutomaticZenRule.java32
-rw-r--r--core/java/android/app/FullscreenRequestHandler.java24
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java41
-rw-r--r--core/java/android/appwidget/flags.aconfig7
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java37
-rw-r--r--core/java/android/content/pm/ILauncherApps.aidl3
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/LauncherApps.java72
-rw-r--r--core/java/android/content/pm/PackageInfo.java2
-rw-r--r--core/java/android/content/pm/PackageInstaller.java11
-rw-r--r--core/java/android/content/pm/PackageManager.java19
-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/camera2/CameraMetadata.java2
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java4
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java4
-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/os/Parcel.java2
-rw-r--r--core/java/android/os/flags.aconfig7
-rw-r--r--core/java/android/service/notification/Condition.java24
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java1
-rw-r--r--core/java/android/service/persistentdata/OWNERS1
-rw-r--r--core/java/android/service/voice/HotwordRejectedResult.java20
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java6
-rw-r--r--core/java/android/service/voice/flags/flags.aconfig7
-rw-r--r--core/java/android/view/ISurfaceControlViewHostParent.aidl3
-rw-r--r--core/java/android/view/IWindowSession.aidl6
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java1
-rw-r--r--core/java/android/view/SurfaceView.java38
-rw-r--r--core/java/android/view/View.java5
-rw-r--r--core/java/android/view/ViewRootImpl.java121
-rw-r--r--core/java/android/view/WindowManager.java10
-rw-r--r--core/java/android/view/WindowlessWindowManager.java19
-rw-r--r--core/java/android/view/flags/refresh_rate_flags.aconfig8
-rw-r--r--core/java/android/widget/RemoteViews.java19
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl2
-rw-r--r--core/java/com/android/internal/app/SuspendedAppActivity.java11
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java18
-rw-r--r--core/java/com/android/internal/jank/Cuj.java9
-rw-r--r--core/java/com/android/internal/net/TEST_MAPPING2
-rw-r--r--core/java/com/android/internal/pm/parsing/AppInfoUtils.java124
-rw-r--r--core/java/com/android/internal/pm/parsing/PackageParserException.java30
-rw-r--r--core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java128
-rw-r--r--core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java (renamed from services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java)76
-rw-r--r--core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java (renamed from services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java)10
-rw-r--r--core/java/com/android/internal/pm/pkg/SEInfoUtil.java30
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java)10
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java)23
-rw-r--r--core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java (renamed from services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java)8
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java)17
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java)13
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java)9
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java)4
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java)11
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java)3
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java)16
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java)8
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java)13
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java)5
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java)11
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java)9
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java)13
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java)8
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java)11
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java)14
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java)8
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java)11
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java)5
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java)7
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java)9
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java)14
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java)7
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java)11
-rw-r--r--core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java (renamed from services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java)98
-rw-r--r--core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java (renamed from services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java)9
-rw-r--r--core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java (renamed from services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java)6
-rw-r--r--core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java (renamed from services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java)6
-rw-r--r--core/java/com/android/internal/pm/split/SplitAssetLoader.java (renamed from services/core/java/com/android/server/pm/split/SplitAssetLoader.java)2
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java15
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java15
-rw-r--r--core/java/com/android/internal/widget/LockscreenCredential.java10
-rw-r--r--core/java/com/android/server/pm/pkg/AndroidPackage.java7
-rw-r--r--core/jni/android_util_Process.cpp40
-rw-r--r--core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp14
-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/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/app/AutomaticZenRuleTest.java74
-rw-r--r--core/tests/coretests/src/android/os/BundleTest.java4
-rw-r--r--core/tests/coretests/src/android/os/MessageQueueTest.java2
-rw-r--r--core/tests/coretests/src/android/os/ParcelTest.java6
-rw-r--r--core/tests/coretests/src/android/service/notification/ConditionTest.java59
-rw-r--r--core/tests/coretests/src/android/util/SparseSetArrayTest.java1
-rw-r--r--core/tests/utiltests/src/android/util/TimeUtilsTest.java10
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java12
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java2
-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/common/split/DividerView.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java12
-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.java41
-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/common/split/DividerViewTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java52
-rw-r--r--libs/input/tests/Android.bp3
-rw-r--r--libs/input/tests/PointerController_test.cpp37
-rw-r--r--media/OWNERS1
-rw-r--r--media/java/android/media/OWNERS1
-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/PackageInstaller/res/values/strings.xml5
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java17
-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/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt6
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java26
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java464
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java231
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig7
-rw-r--r--packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt1
-rw-r--r--packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt246
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt75
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt15
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt95
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt95
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt26
-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/ObservableTransitionState.kt18
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt204
-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.kt83
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt109
-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.kt102
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt20
-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/communal/domain/interactor/CommunalInteractorTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt20
-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/keyguard/ui/preview/KeyguardRemotePreviewManagerTest.kt40
-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/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt172
-rw-r--r--packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java1
-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/drawable/arrow_pointing_down.xml26
-rw-r--r--packages/SystemUI/res/layout/record_issue_dialog.xml81
-rw-r--r--packages/SystemUI/res/layout/sidefps_view.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml20
-rw-r--r--packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java56
-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/communal/domain/interactor/CommunalInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt195
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt4
-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/compose/BaseComposeFacade.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt25
-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.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt8
-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/preview/KeyguardRemotePreviewManager.kt103
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt2
-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.kt50
-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.kt113
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java35
-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/src/com/android/systemui/util/kotlin/Log.kt40
-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/contrast/ContrastDialogDelegateTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java8
-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/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt1
-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.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt94
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java2
-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/data/repository/FakeKeyguardRepository.kt8
-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/smartspace/data/repository/FakeSmartspaceRepository.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt4
-rw-r--r--packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java260
-rw-r--r--ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java79
-rw-r--r--ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java6
-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.aconfig7
-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.java31
-rw-r--r--services/core/java/com/android/server/BatteryService.java15
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java7
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java87
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/am/AppStartInfoTracker.java122
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java7
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java7
-rw-r--r--services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java30
-rw-r--r--services/core/java/com/android/server/app/GameManagerService.java9
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java3
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java2
-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/face/FaceService.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java40
-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/content/SyncManager.java4
-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/hdmi/HdmiCecLocalDeviceTv.java7
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java19
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java13
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java55
-rw-r--r--services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java2
-rw-r--r--services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java6
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java63
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStorage.java4
-rw-r--r--services/core/java/com/android/server/locksettings/UnifiedProfilePasswordCache.java (renamed from services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java)34
-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.java15
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java4
-rw-r--r--services/core/java/com/android/server/pdb/PersistentDataBlockService.java4
-rw-r--r--services/core/java/com/android/server/pm/BroadcastHelper.java13
-rw-r--r--services/core/java/com/android/server/pm/Computer.java13
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java38
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java6
-rw-r--r--services/core/java/com/android/server/pm/IPackageManagerBase.java18
-rw-r--r--services/core/java/com/android/server/pm/InitAppsHelper.java4
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java23
-rw-r--r--services/core/java/com/android/server/pm/InstallRequest.java5
-rw-r--r--services/core/java/com/android/server/pm/KnownPackages.java4
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java53
-rw-r--r--services/core/java/com/android/server/pm/PackageArchiver.java61
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerInternalBase.java26
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java72
-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.java35
-rw-r--r--services/core/java/com/android/server/pm/RemovePackageHelper.java181
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java4
-rw-r--r--services/core/java/com/android/server/pm/ScanRequest.java2
-rw-r--r--services/core/java/com/android/server/pm/Settings.java40
-rw-r--r--services/core/java/com/android/server/pm/SharedUserSetting.java4
-rw-r--r--services/core/java/com/android/server/pm/StorageEventHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/SuspendPackageHelper.java171
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java10
-rw-r--r--services/core/java/com/android/server/pm/UserTypeFactory.java1
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageCacher.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java69
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageParser2.java20
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java65
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java5
-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/SELinuxUtil.java6
-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/pm/resolution/ComponentResolver.java4
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java131
-rw-r--r--services/core/java/com/android/server/policy/TalkbackShortcutController.java118
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java14
-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/ActivityMetricsLaunchObserver.java9
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java6
-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/ActivityTaskManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java28
-rw-r--r--services/core/java/com/android/server/wm/ClientLifecycleManager.java107
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java20
-rw-r--r--services/core/java/com/android/server/wm/DragState.java7
-rw-r--r--services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java18
-rw-r--r--services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java20
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java3
-rw-r--r--services/core/java/com/android/server/wm/Session.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java43
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java4
-rw-r--r--services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp4
-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/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt2
-rw-r--r--services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java2
-rw-r--r--services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt6
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java16
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java142
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java34
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java17
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java8
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt3
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java81
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt44
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt22
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt14
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt10
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt12
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt6
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt7
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt100
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java14
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java22
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt114
-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/hdmi/HdmiCecLocalDeviceTvTest.java62
-rw-r--r--services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt4
-rw-r--r--services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java5
-rw-r--r--services/tests/uiservicestests/Android.bp1
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java61
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java13
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java19
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java43
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java28
-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--services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java117
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java4
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java6
-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/android/telephony/satellite/NtnSignalStrength.java3
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteManager.java21
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl19
-rw-r--r--tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt3
-rw-r--r--tools/aapt2/integration-tests/SymlinkTest/Android.bp3
-rw-r--r--tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java22
554 files changed, 14333 insertions, 3505 deletions
diff --git a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
index 6d1e6d0cbd73..4352c8ae982e 100644
--- a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
@@ -24,10 +24,11 @@ import android.content.pm.parsing.result.ParseTypeImpl
import android.content.res.TypedArray
import android.perftests.utils.BenchmarkState
import android.perftests.utils.PerfStatusReporter
+import android.util.ArraySet
import androidx.test.filters.LargeTest
+import com.android.internal.pm.parsing.pkg.PackageImpl
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.internal.util.ConcurrentUtils
-import com.android.server.pm.parsing.pkg.PackageImpl
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import java.io.File
import java.io.FileOutputStream
import java.util.concurrent.ArrayBlockingQueue
@@ -214,7 +215,10 @@ public class PackageParsingPerfTest {
path,
manifestArray,
isCoreApp,
+ this,
)
+ override fun getHiddenApiWhitelistedApps() = ArraySet<String>()
+ override fun getInstallConstraintsAllowlist() = ArraySet<String>()
})
override fun parseImpl(file: File) =
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index 03891bbec56a..e3ba50dc635b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -26,6 +26,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -319,8 +320,8 @@ public final class BackgroundJobsController extends StateController {
final boolean isStopped = mPackageManagerInternal.isPackageStopped(packageName, uid);
mPackageStoppedState.add(uid, packageName, isStopped);
return isStopped;
- } catch (IllegalArgumentException e) {
- Slog.d(TAG, "Couldn't determine stopped state for unknown package: " + packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "Couldn't determine stopped state for unknown package: " + packageName);
return false;
}
}
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 83e3fabe475b..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
@@ -5285,9 +5286,10 @@ package android.app {
field public static final int START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START = 21; // 0x15
field public static final int START_TIMESTAMP_RESERVED_RANGE_SYSTEM = 20; // 0x14
field public static final int START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE = 7; // 0x7
- field public static final int START_TYPE_COLD = 0; // 0x0
- field public static final int START_TYPE_HOT = 2; // 0x2
- field public static final int START_TYPE_WARM = 1; // 0x1
+ field public static final int START_TYPE_COLD = 1; // 0x1
+ field public static final int START_TYPE_HOT = 3; // 0x3
+ field public static final int START_TYPE_UNSET = 0; // 0x0
+ field public static final int START_TYPE_WARM = 2; // 0x2
}
public final class AsyncNotedAppOp implements android.os.Parcelable {
@@ -12605,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
@@ -13295,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 9f56933865db..802354e08653 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4091,7 +4091,7 @@ package android.content.pm {
field @Deprecated public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
field public static final int MATCH_ANY_USER = 4194304; // 0x400000
- field @Deprecated public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
+ field public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
field @FlaggedApi("android.content.pm.fix_duplicated_flags") public static final long MATCH_CLONE_PROFILE_LONG = 17179869184L; // 0x400000000L
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
@@ -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;
}
@@ -13051,7 +13052,7 @@ package android.service.voice {
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.HotwordDetector.Callback);
method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.VisualQueryDetector createVisualQueryDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.VisualQueryDetector.Callback);
- method @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public void setIsReceiveSandboxedTrainingDataAllowed(boolean);
+ method @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public void setShouldReceiveSandboxedTrainingData(boolean);
}
}
@@ -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);
@@ -16987,7 +16989,7 @@ package android.telephony.satellite {
method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getSatelliteAttachRestrictionReasonsForCarrier(int);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingSatelliteDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatelliteService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForNtnSignalStrengthChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.NtnSignalStrengthCallback);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void registerForNtnSignalStrengthChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.NtnSignalStrengthCallback) throws android.telephony.satellite.SatelliteManager.SatelliteException;
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteCapabilitiesChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteCapabilitiesCallback);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteDatagram(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDatagramCallback);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteStateCallback);
@@ -16999,7 +17001,7 @@ package android.telephony.satellite {
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteProvisioned(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void requestIsSatelliteSupported(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestNtnSignalStrength(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.NtnSignalStrength,android.telephony.satellite.SatelliteManager.SatelliteException>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestNtnSignalStrength(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.NtnSignalStrength,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteCapabilities(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteEnabled(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
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/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8b39ed6fb411..6ddb36a72aa9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4077,7 +4077,7 @@ public final class ActivityThread extends ClientTransactionHandler
final LoadedApk sdkApk = getPackageInfo(
contextInfo.getSdkApplicationInfo(),
r.packageInfo.getCompatibilityInfo(),
- ActivityContextInfo.CONTEXT_FLAGS);
+ contextInfo.getContextFlags());
final ContextImpl activityContext = ContextImpl.createActivityContext(
this, sdkApk, r.activityInfo, r.token, displayId, r.overrideConfig);
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/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java
index c8317c8faad5..656feb0401d6 100644
--- a/core/java/android/app/ApplicationStartInfo.java
+++ b/core/java/android/app/ApplicationStartInfo.java
@@ -104,14 +104,17 @@ public final class ApplicationStartInfo implements Parcelable {
/** Process started due to Activity started for any reason not explicitly listed. */
public static final int START_REASON_START_ACTIVITY = 11;
+ /** Start type not yet set. */
+ public static final int START_TYPE_UNSET = 0;
+
/** Process started from scratch. */
- public static final int START_TYPE_COLD = 0;
+ public static final int START_TYPE_COLD = 1;
/** Process retained minimally SavedInstanceState. */
- public static final int START_TYPE_WARM = 1;
+ public static final int START_TYPE_WARM = 2;
/** Process brought back to foreground. */
- public static final int START_TYPE_HOT = 2;
+ public static final int START_TYPE_HOT = 3;
/**
* Default. The system always creates a new instance of the activity in the target task and
@@ -277,6 +280,7 @@ public final class ApplicationStartInfo implements Parcelable {
@IntDef(
prefix = {"START_TYPE_"},
value = {
+ START_TYPE_UNSET,
START_TYPE_COLD,
START_TYPE_WARM,
START_TYPE_HOT,
@@ -769,6 +773,7 @@ public final class ApplicationStartInfo implements Parcelable {
private static String startTypeToString(@StartType int startType) {
return switch (startType) {
+ case START_TYPE_UNSET -> "UNSET";
case START_TYPE_COLD -> "COLD";
case START_TYPE_WARM -> "WARM";
case START_TYPE_HOT -> "HOT";
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index d93544972e7a..343348b89625 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -16,6 +16,8 @@
package android.app;
+import static com.android.internal.util.Preconditions.checkArgument;
+
import android.annotation.DrawableRes;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -390,7 +392,7 @@ public final class AutomaticZenRule implements Parcelable {
*/
@FlaggedApi(Flags.FLAG_MODES_API)
public void setType(@Type int type) {
- mType = type;
+ mType = checkValidType(type);
}
/**
@@ -451,6 +453,24 @@ public final class AutomaticZenRule implements Parcelable {
mAllowManualInvocation = allowManualInvocation;
}
+ /** @hide */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public void validate() {
+ if (Flags.modesApi()) {
+ checkValidType(mType);
+ }
+ }
+
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ @Type
+ private static int checkValidType(@Type int type) {
+ checkArgument(type >= TYPE_UNKNOWN && type <= TYPE_MANAGED,
+ "Rule type must be one of TYPE_UNKNOWN, TYPE_OTHER, TYPE_SCHEDULE_TIME, "
+ + "TYPE_SCHEDULE_CALENDAR, TYPE_BEDTIME, TYPE_DRIVING, TYPE_IMMERSIVE, "
+ + "TYPE_THEATER, or TYPE_MANAGED");
+ return type;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -625,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);
}
/**
@@ -703,10 +723,10 @@ public final class AutomaticZenRule implements Parcelable {
}
/**
- * Sets the type of the rule
+ * Sets the type of the rule.
*/
public @NonNull Builder setType(@Type int type) {
- mType = type;
+ mType = checkValidType(type);
return this;
}
@@ -714,7 +734,7 @@ public final class AutomaticZenRule implements Parcelable {
* Sets a user visible description of when this rule will be active
* (see {@link Condition#STATE_TRUE}).
*
- * A description should be a (localized) string like "Mon-Fri, 9pm-7am" or
+ * <p>A description should be a (localized) string like "Mon-Fri, 9pm-7am" or
* "When connected to [Car Name]".
*/
public @NonNull Builder setTriggerDescription(@Nullable String description) {
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/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 6e451479c5a4..4cf9fcab9092 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -16,6 +16,8 @@
package android.appwidget;
+import static android.appwidget.flags.Flags.remoteAdapterConversion;
+
import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -566,11 +568,9 @@ public class AppWidgetManager {
private void tryAdapterConversion(
FunctionalUtils.RemoteExceptionIgnoringConsumer<RemoteViews> action,
RemoteViews original, String failureMsg) {
- final boolean isConvertingAdapter = RemoteViews.isAdapterConversionEnabled()
+ if (remoteAdapterConversion()
&& (mHasPostedLegacyLists = mHasPostedLegacyLists
- || (original != null && original.hasLegacyLists()));
-
- if (isConvertingAdapter) {
+ || (original != null && original.hasLegacyLists()))) {
final RemoteViews viewsCopy = new RemoteViews(original);
Runnable updateWidgetWithTask = () -> {
try {
@@ -587,13 +587,12 @@ public class AppWidgetManager {
}
updateWidgetWithTask.run();
- return;
- }
-
- try {
- action.acceptOrThrow(original);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
+ } else {
+ try {
+ action.acceptOrThrow(original);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
}
}
@@ -838,22 +837,20 @@ public class AppWidgetManager {
return;
}
- if (!RemoteViews.isAdapterConversionEnabled()) {
+ if (remoteAdapterConversion()) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ mHasPostedLegacyLists = true;
+ createUpdateExecutorIfNull().execute(() -> notifyCollectionWidgetChange(
+ appWidgetIds, viewId));
+ } else {
+ notifyCollectionWidgetChange(appWidgetIds, viewId);
+ }
+ } else {
try {
mService.notifyAppWidgetViewDataChanged(mPackageName, appWidgetIds, viewId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
-
- return;
- }
-
- if (Looper.myLooper() == Looper.getMainLooper()) {
- mHasPostedLegacyLists = true;
- createUpdateExecutorIfNull().execute(() -> notifyCollectionWidgetChange(appWidgetIds,
- viewId));
- } else {
- notifyCollectionWidgetChange(appWidgetIds, viewId);
}
}
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index 6a735a418b58..c95b864c08bb 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -6,3 +6,10 @@ flag {
description: "Enable support for generated previews in AppWidgetManager"
bug: "306546610"
}
+
+flag {
+ name: "remote_adapter_conversion"
+ namespace: "app_widgets"
+ description: "Enable adapter conversion to RemoteCollectionItemsAdapter"
+ bug: "245950570"
+} \ No newline at end of file
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 e9f419e9a8ce..a97de6368b8c 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -64,6 +64,9 @@ interface ILauncherApps {
PendingIntent getActivityLaunchIntent(String callingPackage, in ComponentName component,
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 0cd4358b2c91..1d2b1aff46bc 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -799,6 +799,78 @@ 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.
+ *
+ * <p>An empty list denotes that all system packages are installed for that user at creation.
+ * This behaviour is inherited from the underlining UserManager API.
+ *
+ * @param userHandle the user for which installed system packages are required.
+ * @return {@link List} of {@link String}, representing the package name of the installed
+ * package. Can be empty but not null.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
+ public List<String> getPreInstalledSystemPackages(@NonNull UserHandle userHandle) {
+ if (DEBUG) {
+ Log.i(TAG, "getPreInstalledSystemPackages for user: " + userHandle);
+ }
+ try {
+ return mService.getPreInstalledSystemPackages(userHandle);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
/**
* Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
* returns null.
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 5dee65b62201..4f61613b9c6e 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -231,7 +231,7 @@ public class PackageInfo implements Parcelable {
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PERMISSIONS} was set. Each value matches
* the corresponding entry in {@link #requestedPermissions}, and will have
- * the flags {@link #REQUESTED_PERMISSION_GRANTED} and
+ * the flags {@link #REQUESTED_PERMISSION_GRANTED}, {@link #REQUESTED_PERMISSION_IMPLICIT}, and
* {@link #REQUESTED_PERMISSION_NEVER_FOR_LOCATION} set as appropriate.
*/
@Nullable
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 4d75a5147d6e..a8638708824b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1225,12 +1225,10 @@ public abstract class PackageManager {
public static final int MATCH_DEBUG_TRIAGED_MISSING = MATCH_DIRECT_BOOT_AUTO;
/**
- * @deprecated Use {@link #MATCH_CLONE_PROFILE_LONG} instead.
+ * Use {@link #MATCH_CLONE_PROFILE_LONG} instead.
*
* @hide
*/
- @SuppressLint("UnflaggedApi") // Just adding the @Deprecated annotation
- @Deprecated
@SystemApi
public static final int MATCH_CLONE_PROFILE = 0x20000000;
@@ -1519,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 {}
@@ -1766,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.
*
@@ -9992,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/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 93fbe8aee8d4..7cf10d89004f 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1216,7 +1216,7 @@ public abstract class CameraMetadata<TKey> {
* <ul>
* <li>Profile {@link android.hardware.camera2.params.DynamicRangeProfiles#HLG10 }</li>
* <li>All mandatory stream combinations for this specific capability as per
- * <a href="CameraDevice#10-bit-output-additional-guaranteed-configurations">documentation</a></li>
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#10-bit-output-additional-guaranteed-configurations">documentation</a></li>
* <li>In case the device is not able to capture some combination of supported
* standard 8-bit and/or 10-bit dynamic range profiles within the same capture request,
* then those constraints must be listed in
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 06397c9a1598..ded96a23e11e 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1484,7 +1484,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <p>To start a CaptureSession with a target FPS range different from the
* capture request template's default value, the application
* is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the target fps range before creating the capture session. The aeTargetFpsRange is
* typically a session parameter. Specifying it at session creation time helps avoid
* session reconfiguration delays in cases like 60fps or high speed recording.</p>
@@ -2161,7 +2161,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* OFF if the recording output is not stabilized, or if there are no output
* Surface types that can be stabilized.</p>
* <p>The application is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the desired video stabilization mode before creating the capture session.
* Video stabilization mode is a session parameter on many devices. Specifying
* it at session creation time helps avoid reconfiguration delay caused by difference
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index ab4406c37c8e..1d26d69a58b9 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -899,7 +899,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p>To start a CaptureSession with a target FPS range different from the
* capture request template's default value, the application
* is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the target fps range before creating the capture session. The aeTargetFpsRange is
* typically a session parameter. Specifying it at session creation time helps avoid
* session reconfiguration delays in cases like 60fps or high speed recording.</p>
@@ -2382,7 +2382,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* OFF if the recording output is not stabilized, or if there are no output
* Surface types that can be stabilized.</p>
* <p>The application is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the desired video stabilization mode before creating the capture session.
* Video stabilization mode is a session parameter on many devices. Specifying
* it at session creation time helps avoid reconfiguration delay caused by difference
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/os/Parcel.java b/core/java/android/os/Parcel.java
index f2930fe45295..8e860c35388d 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -465,9 +465,7 @@ public final class Parcel {
private static native byte[] nativeMarshall(long nativePtr);
private static native void nativeUnmarshall(
long nativePtr, byte[] data, int offset, int length);
- @RavenwoodThrow
private static native int nativeCompareData(long thisNativePtr, long otherNativePtr);
- @RavenwoodThrow
private static native boolean nativeCompareDataInRange(
long ptrA, int offsetA, long ptrB, int offsetB, int length);
private static native void nativeAppendFrom(
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 145981c92283..83d237d6e53b 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -78,6 +78,13 @@ flag {
}
flag {
+ name: "adpf_use_fmq_channel"
+ namespace: "game"
+ description: "Guards use of the FMQ channel for ADPF"
+ bug: "315894228"
+}
+
+flag {
name: "battery_service_support_current_adb_command"
namespace: "backstage_power"
description: "Whether or not BatteryService supports adb commands for Current values."
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 531626b1e85f..6e771f8f0ffe 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (c) 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,8 @@
package android.service.notification;
+import static com.android.internal.util.Preconditions.checkArgument;
+
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -117,7 +119,7 @@ public final class Condition implements Parcelable {
/** The source of, or reason for, the state change represented by this Condition. **/
@FlaggedApi(Flags.FLAG_MODES_API)
- public final @Source int source;
+ public final @Source int source; // default = SOURCE_UNKNOWN
/**
* The maximum string length for any string contained in this condition.
@@ -179,7 +181,7 @@ public final class Condition implements Parcelable {
this.line2 = getTrimmedString(line2);
this.icon = icon;
this.state = state;
- this.source = source;
+ this.source = checkValidSource(source);
this.flags = flags;
}
@@ -197,10 +199,26 @@ public final class Condition implements Parcelable {
source.readInt());
}
+ /** @hide */
+ public void validate() {
+ if (Flags.modesApi()) {
+ checkValidSource(source);
+ }
+ }
+
private static boolean isValidState(int state) {
return state >= STATE_FALSE && state <= STATE_ERROR;
}
+ private static int checkValidSource(@Source int source) {
+ if (Flags.modesApi()) {
+ checkArgument(source >= SOURCE_UNKNOWN && source <= SOURCE_CONTEXT,
+ "Condition source must be one of SOURCE_UNKNOWN, SOURCE_USER_ACTION, "
+ + "SOURCE_SCHEDULE, or SOURCE_CONTEXT");
+ }
+ return source;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(id, 0);
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index a5b087c05dfa..fcdc5fe71e4e 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1980,6 +1980,7 @@ public class ZenModeConfig implements Parcelable {
@Nullable public ZenDeviceEffects zenDeviceEffects;
public boolean modified; // rule has been modified from initial creation
public String pkg;
+ @AutomaticZenRule.Type
public int type = AutomaticZenRule.TYPE_UNKNOWN;
public String triggerDescription;
public String iconResName;
diff --git a/core/java/android/service/persistentdata/OWNERS b/core/java/android/service/persistentdata/OWNERS
new file mode 100644
index 000000000000..6dfb888dedad
--- /dev/null
+++ b/core/java/android/service/persistentdata/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pdb/OWNERS
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/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index fba09233e4f4..75ab48a43da6 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -1042,13 +1042,13 @@ public class VoiceInteractionService extends Service {
@SystemApi
@FlaggedApi(Flags.FLAG_ALLOW_TRAINING_DATA_EGRESS_FROM_HDS)
@RequiresPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION)
- public void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed) {
- Log.i(TAG, "setIsReceiveSandboxedTrainingDataAllowed to " + allowed);
+ public void setShouldReceiveSandboxedTrainingData(boolean allowed) {
+ Log.i(TAG, "setShouldReceiveSandboxedTrainingData to " + allowed);
if (mSystemService == null) {
throw new IllegalStateException("Not available until onReady() is called");
}
try {
- mSystemService.setIsReceiveSandboxedTrainingDataAllowed(allowed);
+ mSystemService.setShouldReceiveSandboxedTrainingData(allowed);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
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/ISurfaceControlViewHostParent.aidl b/core/java/android/view/ISurfaceControlViewHostParent.aidl
index f42e00148587..559c20ee4825 100644
--- a/core/java/android/view/ISurfaceControlViewHostParent.aidl
+++ b/core/java/android/view/ISurfaceControlViewHostParent.aidl
@@ -16,6 +16,7 @@
package android.view;
+import android.view.KeyEvent;
import android.view.WindowManager;
/**
@@ -24,4 +25,6 @@ import android.view.WindowManager;
*/
oneway interface ISurfaceControlViewHostParent {
void updateParams(in WindowManager.LayoutParams[] childAttrs);
+ // To forward the back key event from embedded to host app.
+ void forwardBackKeyToParent(in KeyEvent keyEvent);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index dbacca5def51..9bf43a390d70 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -162,6 +162,8 @@ interface IWindowSession {
* @param flags See {@code View#startDragAndDrop}
* @param surface Surface containing drag shadow image
* @param touchSource See {@code InputDevice#getSource()}
+ * @param touchDeviceId device ID of last touch event
+ * @param pointerId pointer ID of last touch event
* @param touchX X coordinate of last touch point
* @param touchY Y coordinate of last touch point
* @param thumbCenterX X coordinate for the position within the shadow image that should be
@@ -171,9 +173,9 @@ interface IWindowSession {
* @param data Data transferred by drag and drop
* @return Token of drag operation which will be passed to cancelDragAndDrop.
*/
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
IBinder performDrag(IWindow window, int flags, in SurfaceControl surface, int touchSource,
- float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data);
+ int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX,
+ float thumbCenterY, in ClipData data);
/**
* Drops the content of the current drag operation for accessibility
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 405653123f79..4840f003da3e 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -447,6 +447,7 @@ public class SurfaceControlViewHost {
addWindowToken(attrs);
view.setLayoutParams(attrs);
mViewRoot.setView(view, attrs, null);
+ mViewRoot.setBackKeyCallbackForWindowlessWindow(mWm::forwardBackKeyToParent);
}
/**
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a44a95a1677f..108de281a411 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -37,6 +37,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RenderNode;
+import android.hardware.input.InputManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -159,6 +160,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private static final boolean DEBUG = false;
private static final boolean DEBUG_POSITION = false;
+ private static final long FORWARD_BACK_KEY_TOLERANCE_MS = 100;
+
@UnsupportedAppUsage(
maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
publicAlternatives = "Track {@link SurfaceHolder#addCallback} instead")
@@ -326,6 +329,41 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
});
}
}
+
+ @Override
+ public void forwardBackKeyToParent(@NonNull KeyEvent keyEvent) {
+ runOnUiThread(() -> {
+ if (!isAttachedToWindow() || keyEvent.getKeyCode() != KeyEvent.KEYCODE_BACK) {
+ return;
+ }
+ final ViewRootImpl vri = getViewRootImpl();
+ if (vri == null) {
+ return;
+ }
+ final InputManager inputManager = mContext.getSystemService(InputManager.class);
+ if (inputManager == null) {
+ return;
+ }
+ // Check that the event was created recently.
+ final long timeDiff = SystemClock.uptimeMillis() - keyEvent.getEventTime();
+ if (timeDiff > FORWARD_BACK_KEY_TOLERANCE_MS) {
+ Log.e(TAG, "Ignore the input event that exceed the tolerance time, "
+ + "exceed " + timeDiff + "ms");
+ return;
+ }
+ if (inputManager.verifyInputEvent(keyEvent) == null) {
+ Log.e(TAG, "Received invalid input event");
+ return;
+ }
+ try {
+ vri.processingBackKey(true);
+ vri.enqueueInputEvent(keyEvent, null /* receiver */, 0 /* flags */,
+ true /* processImmediately */);
+ } finally {
+ vri.processingBackKey(false);
+ }
+ });
+ }
};
private final boolean mRtDrivenClipping = Flags.clipSurfaceviews();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 75f8eba01fa2..bb5ee0359b6b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -28340,6 +28340,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
IBinder token = mAttachInfo.mSession.performDrag(
mAttachInfo.mWindow, flags, null,
mAttachInfo.mViewRootImpl.getLastTouchSource(),
+ mAttachInfo.mViewRootImpl.getLastTouchDeviceId(),
+ mAttachInfo.mViewRootImpl.getLastTouchPointerId(),
0f, 0f, 0f, 0f, data);
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token);
@@ -28414,7 +28416,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl,
- root.getLastTouchSource(), lastTouchPoint.x, lastTouchPoint.y,
+ root.getLastTouchSource(), root.getLastTouchDeviceId(),
+ root.getLastTouchPointerId(), lastTouchPoint.x, lastTouchPoint.y,
shadowTouchPoint.x, shadowTouchPoint.y, data);
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "performDrag returned " + token);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5cbb42e0e346..e83488e2689e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -76,13 +76,8 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_E
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -96,6 +91,7 @@ import static android.view.accessibility.Flags.reduceWindowContentChangedEventTh
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
+import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
import static com.android.input.flags.Flags.enablePointerChoreographer;
@@ -255,7 +251,7 @@ import java.util.OptionalInt;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
-import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* The top of a view hierarchy, implementing the needed protocol between View
@@ -375,6 +371,8 @@ public final class ViewRootImpl implements ViewParent,
*/
private static final int KEEP_CLEAR_AREA_REPORT_RATE_MILLIS = 100;
+ private static final long NANOS_PER_SEC = 1000000000;
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
@@ -620,6 +618,13 @@ public final class ViewRootImpl implements ViewParent,
boolean mUpcomingWindowFocus;
@GuardedBy("this")
boolean mUpcomingInTouchMode;
+ // While set, allow this VRI to handle back key without drop it.
+ private boolean mProcessingBackKey;
+ /**
+ * Compatibility {@link OnBackInvokedCallback} for windowless window, to forward the back
+ * key event host app.
+ */
+ private Predicate<KeyEvent> mWindowlessBackKeyCallback;
public boolean mTraversalScheduled;
int mTraversalBarrier;
@@ -808,6 +813,8 @@ public final class ViewRootImpl implements ViewParent,
final PointF mDragPoint = new PointF();
final PointF mLastTouchPoint = new PointF();
int mLastTouchSource;
+ int mLastTouchDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
+ int mLastTouchPointerId;
/** Tracks last {@link MotionEvent#getToolType(int)} with {@link MotionEvent#ACTION_UP}. **/
private int mLastClickToolType;
@@ -822,6 +829,8 @@ public final class ViewRootImpl implements ViewParent,
private boolean mInsetsAnimationRunning;
+ private long mPreviousFrameDrawnTime = -1;
+
/**
* The resolved pointer icon type requested by this window.
* A null value indicates the resolved pointer icon has not yet been calculated.
@@ -1059,11 +1068,14 @@ public final class ViewRootImpl implements ViewParent,
private boolean mChildBoundingInsetsChanged = false;
private String mTag = TAG;
+ private String mFpsTraceName;
private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
+ private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
static {
sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
+ sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision();
}
// The latest input event from the gesture that was used to resolve the pointer icon.
@@ -1307,6 +1319,7 @@ public final class ViewRootImpl implements ViewParent,
attrs = mWindowAttributes;
setTag();
+ mFpsTraceName = "FPS of " + getTitle();
if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
& WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
@@ -3194,7 +3207,11 @@ public final class ViewRootImpl implements ViewParent,
host.dispatchAttachedToWindow(mAttachInfo, 0);
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
dispatchApplyInsets(host);
- if (!mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
+ if (!mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()
+ // Don't register compat OnBackInvokedCallback for windowless window.
+ // The onBackInvoked event by default should forward to host app, so the
+ // host app can decide the behavior.
+ && mWindowlessBackKeyCallback == null) {
// For apps requesting legacy back behavior, we add a compat callback that
// dispatches {@link KeyEvent#KEYCODE_BACK} to their root views.
// This way from system point of view, these apps are providing custom
@@ -4726,6 +4743,31 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ /**
+ * Called from draw() to collect metrics for frame rate decision.
+ */
+ private void collectFrameRateDecisionMetrics() {
+ if (!Trace.isEnabled()) {
+ if (mPreviousFrameDrawnTime > 0) mPreviousFrameDrawnTime = -1;
+ return;
+ }
+
+ if (mPreviousFrameDrawnTime < 0) {
+ mPreviousFrameDrawnTime = mChoreographer.getExpectedPresentationTimeNanos();
+ return;
+ }
+
+ long expectedDrawnTime = mChoreographer.getExpectedPresentationTimeNanos();
+ long timeDiff = expectedDrawnTime - mPreviousFrameDrawnTime;
+ if (timeDiff <= 0) {
+ return;
+ }
+
+ long fps = NANOS_PER_SEC / timeDiff;
+ Trace.setCounter(mFpsTraceName, fps);
+ mPreviousFrameDrawnTime = expectedDrawnTime;
+ }
+
private void reportDrawFinished(@Nullable Transaction t, int seqId) {
if (DEBUG_BLAST) {
Log.d(mTag, "reportDrawFinished");
@@ -5044,6 +5086,9 @@ public final class ViewRootImpl implements ViewParent,
if (DEBUG_FPS) {
trackFPS();
}
+ if (sToolkitMetricsForFrameRateDecisionFlagValue) {
+ collectFrameRateDecisionMetrics();
+ }
if (!sFirstDrawComplete) {
synchronized (sFirstDrawHandlers) {
@@ -6660,7 +6705,8 @@ public final class ViewRootImpl implements ViewParent,
// Find a reason for dropping or canceling the event.
final String reason;
- if (!mAttachInfo.mHasWindowFocus
+ // The embedded window is focused, allow this VRI to handle back key.
+ if (!mAttachInfo.mHasWindowFocus && !(mProcessingBackKey && isBack(q.mEvent))
&& !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
&& !isAutofillUiShowing()) {
// This is a non-pointer event and the window doesn't currently have input focus
@@ -6883,10 +6929,20 @@ public final class ViewRootImpl implements ViewParent,
// If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the
// view tree or IME, and invoke the appropriate {@link OnBackInvokedCallback}.
- if (isBack(keyEvent)
- && mContext != null
- && mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
- return doOnBackKeyEvent(keyEvent);
+ if (isBack(keyEvent)) {
+ if (mWindowlessBackKeyCallback != null) {
+ if (mWindowlessBackKeyCallback.test(keyEvent)) {
+ return keyEvent.getAction() == KeyEvent.ACTION_UP
+ && !keyEvent.isCanceled()
+ ? FINISH_HANDLED : FINISH_NOT_HANDLED;
+ } else {
+ // Unable to forward the back key to host, forward to next stage.
+ return FORWARD;
+ }
+ } else if (mContext != null
+ && mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
+ return doOnBackKeyEvent(keyEvent);
+ }
}
if (mInputQueue != null) {
@@ -7109,6 +7165,8 @@ public final class ViewRootImpl implements ViewParent,
mLastTouchPoint.x = event.getRawX();
mLastTouchPoint.y = event.getRawY();
mLastTouchSource = event.getSource();
+ mLastTouchDeviceId = event.getDeviceId();
+ mLastTouchPointerId = event.getPointerId(0);
// Register last ACTION_UP. This will be propagated to IME.
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
@@ -8520,6 +8578,14 @@ public final class ViewRootImpl implements ViewParent,
return mLastTouchSource;
}
+ public int getLastTouchDeviceId() {
+ return mLastTouchDeviceId;
+ }
+
+ public int getLastTouchPointerId() {
+ return mLastTouchPointerId;
+ }
+
/**
* Used by InputMethodManager.
* @hide
@@ -10529,6 +10595,11 @@ public final class ViewRootImpl implements ViewParent,
mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, listener).sendToTarget();
}
+ // Make this VRI able to process back key without drop it.
+ void processingBackKey(boolean processing) {
+ mProcessingBackKey = processing;
+ }
+
/**
* Collect and include any ScrollCaptureCallback instances registered with the window.
*
@@ -11753,13 +11824,18 @@ public final class ViewRootImpl implements ViewParent,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
- enqueueInputEvent(ev);
+ enqueueInputEvent(ev, null /* receiver */, 0 /* flags */, true /* processImmediately */);
}
private void registerCompatOnBackInvokedCallback() {
mCompatOnBackInvokedCallback = () -> {
- sendBackKeyEvent(KeyEvent.ACTION_DOWN);
- sendBackKeyEvent(KeyEvent.ACTION_UP);
+ try {
+ processingBackKey(true);
+ sendBackKeyEvent(KeyEvent.ACTION_DOWN);
+ sendBackKeyEvent(KeyEvent.ACTION_UP);
+ } finally {
+ processingBackKey(false);
+ }
};
if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) {
Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher");
@@ -12097,11 +12173,9 @@ public final class ViewRootImpl implements ViewParent,
boolean desiredAction = motionEventAction == MotionEvent.ACTION_DOWN
|| motionEventAction == MotionEvent.ACTION_MOVE
|| motionEventAction == MotionEvent.ACTION_UP;
- boolean desiredType = windowType == TYPE_BASE_APPLICATION || windowType == TYPE_APPLICATION
- || windowType == TYPE_APPLICATION_STARTING || windowType == TYPE_DRAWN_APPLICATION
- || windowType == TYPE_NOTIFICATION_SHADE || windowType == TYPE_STATUS_BAR;
+ boolean undesiredType = windowType == TYPE_INPUT_METHOD;
// use toolkitSetFrameRate flag to gate the change
- return desiredAction && desiredType && sToolkitSetFrameRateReadOnlyFlagValue;
+ return desiredAction && !undesiredType && sToolkitSetFrameRateReadOnlyFlagValue;
}
/**
@@ -12196,4 +12270,13 @@ public final class ViewRootImpl implements ViewParent,
}
return false;
}
+
+ /**
+ * Set the default back key callback for windowless window, to forward the back key event
+ * to host app.
+ * MUST NOT call this method for normal window.
+ */
+ void setBackKeyCallbackForWindowlessWindow(@NonNull Predicate<KeyEvent> callback) {
+ mWindowlessBackKeyCallback = callback;
+ }
}
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/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index d817e6f51f55..d6ac56239aed 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
@@ -488,8 +489,9 @@ public class WindowlessWindowManager implements IWindowSession {
@Override
public android.os.IBinder performDrag(android.view.IWindow window, int flags,
- android.view.SurfaceControl surface, int touchSource, float touchX, float touchY,
- float thumbCenterX, float thumbCenterY, android.content.ClipData data) {
+ android.view.SurfaceControl surface, int touchSource, int touchDeviceId,
+ int touchPointerId, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+ android.content.ClipData data) {
return null;
}
@@ -703,4 +705,17 @@ public class WindowlessWindowManager implements IWindowSession {
}
}
}
+
+ boolean forwardBackKeyToParent(@NonNull KeyEvent keyEvent) {
+ if (mParentInterface == null) {
+ return false;
+ }
+ try {
+ mParentInterface.forwardBackKeyToParent(keyEvent);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to forward back key To Parent: ", e);
+ return false;
+ }
+ return true;
+ }
}
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index a467afe5d06a..0aa516e08697 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -42,4 +42,12 @@ flag {
namespace: "core_graphics"
description: "Enable the `setFrameRate` callback"
bug: "299946220"
+}
+
+flag {
+ name: "toolkit_metrics_for_frame_rate_decision"
+ namespace: "toolkit"
+ description: "Feature flag for toolkit metrics collecting for frame rate decision"
+ bug: "301343249"
+ is_fixed_read_only: true
} \ No newline at end of file
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index da3134856731..8ad10af7250a 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -16,6 +16,7 @@
package android.widget;
+import static android.appwidget.flags.Flags.remoteAdapterConversion;
import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR;
import android.annotation.AttrRes;
@@ -36,7 +37,6 @@ import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityOptions;
import android.app.ActivityThread;
-import android.app.AppGlobals;
import android.app.Application;
import android.app.LoadedApk;
import android.app.PendingIntent;
@@ -108,7 +108,6 @@ import android.widget.AdapterView.OnItemClickListener;
import android.widget.CompoundButton.OnCheckedChangeListener;
import com.android.internal.R;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.IRemoteViewsFactory;
@@ -4950,21 +4949,11 @@ public class RemoteViews implements Parcelable, Filter {
*/
@Deprecated
public void setRemoteAdapter(@IdRes int viewId, Intent intent) {
- if (isAdapterConversionEnabled()) {
+ if (remoteAdapterConversion()) {
addAction(new SetRemoteCollectionItemListAdapterAction(viewId, intent));
- return;
+ } else {
+ addAction(new SetRemoteViewsAdapterIntent(viewId, intent));
}
- addAction(new SetRemoteViewsAdapterIntent(viewId, intent));
- }
-
- /**
- * @hide
- * @return True if the remote adapter conversion is enabled
- */
- public static boolean isAdapterConversionEnabled() {
- return AppGlobals.getIntCoreSetting(
- SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION,
- SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT ? 1 : 0) != 0;
}
/**
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 82ee8fc47571..e92c6a6c4b34 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -397,5 +397,5 @@ interface IVoiceInteractionManagerService {
* sandboxed detection (from trusted process).
*/
@EnforcePermission("MANAGE_HOTWORD_DETECTION")
- void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed);
+ void setShouldReceiveSandboxedTrainingData(boolean allowed);
}
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/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index e494346bae5c..bd806bfb3e24 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -519,24 +519,6 @@ public final class SystemUiDeviceConfigFlags {
public static final String TASK_MANAGER_SHOW_FOOTER_DOT = "task_manager_show_footer_dot";
/**
- * (boolean) Whether to enable the adapter conversion in RemoteViews
- */
- public static final String REMOTEVIEWS_ADAPTER_CONVERSION =
- "CursorControlFeature__remoteviews_adapter_conversion";
-
- /**
- * The key name used in app core settings for {@link #REMOTEVIEWS_ADAPTER_CONVERSION}
- */
- public static final String KEY_REMOTEVIEWS_ADAPTER_CONVERSION =
- "systemui__remoteviews_adapter_conversion";
-
- /**
- * Default value for whether the adapter conversion is enabled or not. This is set for
- * RemoteViews and should not be a common practice.
- */
- public static final boolean REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT = false;
-
- /**
* (boolean) Whether the task manager should show a stop button if the app is allowlisted
* by the user.
*/
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index f460233f0edd..96740c59ec06 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -109,6 +109,7 @@ public class Cuj {
* eg: Exit the app using back gesture.
*/
public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK = 78;
+ // 79 is reserved.
public static final int CUJ_IME_INSETS_SHOW_ANIMATION = 80;
public static final int CUJ_IME_INSETS_HIDE_ANIMATION = 81;
@@ -119,10 +120,11 @@ public class Cuj {
public static final int CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY = 84;
public static final int CUJ_PREDICTIVE_BACK_CROSS_TASK = 85;
public static final int CUJ_PREDICTIVE_BACK_HOME = 86;
+ public static final int CUJ_LAUNCHER_SEARCH_QSB_OPEN = 87;
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
@VisibleForTesting
- static final int LAST_CUJ = CUJ_PREDICTIVE_BACK_HOME;
+ static final int LAST_CUJ = CUJ_LAUNCHER_SEARCH_QSB_OPEN;
/** @hide */
@IntDef({
@@ -204,6 +206,7 @@ public class Cuj {
CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY,
CUJ_PREDICTIVE_BACK_CROSS_TASK,
CUJ_PREDICTIVE_BACK_HOME,
+ CUJ_LAUNCHER_SEARCH_QSB_OPEN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -295,6 +298,8 @@ public class Cuj {
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_ACTIVITY;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_TASK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_TASK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_HOME] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_HOME;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SEARCH_QSB_OPEN] =
+ FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SEARCH_QSB_OPEN;
}
private Cuj() {
@@ -467,6 +472,8 @@ public class Cuj {
return "PREDICTIVE_BACK_CROSS_TASK";
case CUJ_PREDICTIVE_BACK_HOME:
return "PREDICTIVE_BACK_HOME";
+ case CUJ_LAUNCHER_SEARCH_QSB_OPEN:
+ return "LAUNCHER_SEARCH_QSB_OPEN";
}
return "UNKNOWN";
}
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/AppInfoUtils.java b/core/java/com/android/internal/pm/parsing/AppInfoUtils.java
new file mode 100644
index 000000000000..38a2fe2a77a1
--- /dev/null
+++ b/core/java/com/android/internal/pm/parsing/AppInfoUtils.java
@@ -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.internal.pm.parsing;
+
+import android.annotation.CheckResult;
+import android.content.pm.ApplicationInfo;
+
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
+
+public class AppInfoUtils {
+
+ /**
+ * @see ApplicationInfo#flags
+ */
+ public static int appInfoFlags(AndroidPackage pkg) {
+ // @formatter:off
+ int pkgWithoutStateFlags = flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE)
+ | flag(pkg.isHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED)
+ | flag(pkg.isBackupAllowed(), ApplicationInfo.FLAG_ALLOW_BACKUP)
+ | flag(pkg.isKillAfterRestoreAllowed(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
+ | flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
+ | flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY)
+ | flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT)
+ | flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE)
+ | flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE)
+ | flag(pkg.isDeclaredHavingCode(), ApplicationInfo.FLAG_HAS_CODE)
+ | flag(pkg.isTaskReparentingAllowed(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
+ | flag(pkg.isClearUserDataAllowed(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
+ | flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP)
+ | flag(pkg.isCleartextTrafficAllowed(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
+ | flag(pkg.isRtlSupported(), ApplicationInfo.FLAG_SUPPORTS_RTL)
+ | flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY)
+ | flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH)
+ | flag(pkg.isExtractNativeLibrariesRequested(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
+ | flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME)
+ | flag(pkg.isSmallScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
+ | flag(pkg.isNormalScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
+ | flag(pkg.isLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
+ | flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
+ | flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
+ | flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
+ | flag(AndroidPackageLegacyUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
+ | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST);
+
+ return pkgWithoutStateFlags;
+ // @formatter:on
+ }
+
+ /** @see ApplicationInfo#privateFlags */
+ public static int appInfoPrivateFlags(AndroidPackage pkg) {
+ // @formatter:off
+ int pkgWithoutStateFlags = flag(pkg.isStaticSharedLibrary(), ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY)
+ | flag(pkg.isResourceOverlay(), ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY)
+ | flag(pkg.isIsolatedSplitLoading(), ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING)
+ | flag(pkg.isHasDomainUrls(), ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS)
+ | flag(pkg.isProfileableByShell(), ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL)
+ | flag(pkg.isBackupInForeground(), ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND)
+ | flag(pkg.isUseEmbeddedDex(), ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX)
+ | flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
+ | flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE)
+ | flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE)
+ | flag(pkg.isClearUserDataOnFailedRestoreAllowed(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
+ | flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE)
+ | flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE)
+ | flag(pkg.isNonSdkApiRequested(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
+ | flag(pkg.isUserDataFragile(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
+ | flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+ | flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
+ | flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING)
+ | flag(AndroidPackageLegacyUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
+ | flag(AndroidPackageLegacyUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ | flag(AndroidPackageLegacyUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM)
+ | flag(AndroidPackageLegacyUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR)
+ | flag(AndroidPackageLegacyUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
+ | flag(AndroidPackageLegacyUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM)
+ | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
+
+ Boolean resizeableActivity = pkg.getResizeableActivity();
+ if (resizeableActivity != null) {
+ if (resizeableActivity) {
+ pkgWithoutStateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
+ } else {
+ pkgWithoutStateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
+ }
+ }
+
+ return pkgWithoutStateFlags;
+ // @formatter:on
+ }
+
+
+ /** @see ApplicationInfo#privateFlagsExt */
+ public static int appInfoPrivateFlagsExt(AndroidPackage pkg,
+ boolean isAllowlistedForHiddenApis) {
+ // @formatter:off
+ int pkgWithoutStateFlags = flag(pkg.isProfileable(), ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE)
+ | flag(pkg.hasRequestForegroundServiceExemption(), ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION)
+ | flag(pkg.isAttributionsUserVisible(), ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE)
+ | flag(pkg.isOnBackInvokedCallbackEnabled(), ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK)
+ | flag(isAllowlistedForHiddenApis, ApplicationInfo.PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS);
+ return pkgWithoutStateFlags;
+ // @formatter:on
+ }
+
+ @CheckResult
+ private static int flag(boolean hasFlag, int flag) {
+ return hasFlag ? flag : 0;
+ }
+}
diff --git a/core/java/com/android/internal/pm/parsing/PackageParserException.java b/core/java/com/android/internal/pm/parsing/PackageParserException.java
new file mode 100644
index 000000000000..4250bbd9baf6
--- /dev/null
+++ b/core/java/com/android/internal/pm/parsing/PackageParserException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.pm.parsing;
+
+public class PackageParserException extends Exception {
+ public final int error;
+
+ public PackageParserException(int error, String detailMessage) {
+ super(detailMessage);
+ this.error = error;
+ }
+
+ public PackageParserException(int error, String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ this.error = error;
+ }
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java
new file mode 100644
index 000000000000..e65f1c960b6a
--- /dev/null
+++ b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.pm.parsing.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+
+import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
+import com.android.server.pm.pkg.AndroidPackage;
+
+/** @hide */
+public class AndroidPackageLegacyUtils {
+
+ private AndroidPackageLegacyUtils() {
+ }
+
+ /**
+ * Returns the primary ABI as parsed from the package. Used only during parsing and derivation.
+ * Otherwise prefer {@link PackageState#getPrimaryCpuAbi()}.
+ */
+ public static String getRawPrimaryCpuAbi(AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).getPrimaryCpuAbi();
+ }
+
+ /**
+ * Returns the secondary ABI as parsed from the package. Used only during parsing and
+ * derivation. Otherwise prefer {@link PackageState#getSecondaryCpuAbi()}.
+ */
+ public static String getRawSecondaryCpuAbi(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).getSecondaryCpuAbi();
+ }
+
+ @Deprecated
+ @NonNull
+ public static ApplicationInfo generateAppInfoWithoutState(AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).toAppInfoWithoutState();
+ }
+
+ /**
+ * Replacement of unnecessary legacy getRealPackage. Only returns a value if the package was
+ * actually renamed.
+ */
+ @Nullable
+ public static String getRealPackageOrNull(@NonNull AndroidPackage pkg, boolean isSystem) {
+ if (pkg.getOriginalPackages().isEmpty() || !isSystem) {
+ return null;
+ }
+
+ return pkg.getManifestPackageName();
+ }
+
+ public static void fillVersionCodes(@NonNull AndroidPackage pkg, @NonNull PackageInfo info) {
+ info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode();
+ info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isSystem}
+ */
+ @Deprecated
+ public static boolean isSystem(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isSystem();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isSystemExt}
+ */
+ @Deprecated
+ public static boolean isSystemExt(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isSystemExt();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isPrivileged}
+ */
+ @Deprecated
+ public static boolean isPrivileged(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isPrivileged();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isOem}
+ */
+ @Deprecated
+ public static boolean isOem(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isOem();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isVendor}
+ */
+ @Deprecated
+ public static boolean isVendor(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isVendor();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isProduct}
+ */
+ @Deprecated
+ public static boolean isProduct(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isProduct();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isOdm}
+ */
+ @Deprecated
+ public static boolean isOdm(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isOdm();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index da58d47edbfe..83acc47d637f 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.parsing.pkg;
+package com.android.internal.pm.parsing.pkg;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
@@ -50,47 +50,44 @@ import android.util.SparseIntArray;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.parsing.pkg.AndroidPackageHidden;
-import com.android.internal.pm.parsing.pkg.AndroidPackageInternal;
-import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.AppInfoUtils;
import com.android.internal.pm.pkg.AndroidPackageSplitImpl;
+import com.android.internal.pm.pkg.SEInfoUtil;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
+import com.android.internal.pm.pkg.component.ParsedApexSystemServiceImpl;
import com.android.internal.pm.pkg.component.ParsedAttribution;
+import com.android.internal.pm.pkg.component.ParsedAttributionImpl;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl;
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl;
import com.android.internal.pm.pkg.component.ParsedProcess;
+import com.android.internal.pm.pkg.component.ParsedProcessImpl;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.component.ParsedServiceImpl;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
-import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.AndroidPackageSplit;
-import com.android.server.pm.pkg.SELinuxUtil;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl;
-import com.android.server.pm.pkg.component.ParsedAttributionImpl;
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionImpl;
-import com.android.server.pm.pkg.component.ParsedProcessImpl;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
-import com.android.server.pm.pkg.component.ParsedServiceImpl;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import libcore.util.EmptyArray;
@@ -422,8 +419,10 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
@NonNull
public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath,
- @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) {
- return new PackageImpl(packageName, baseCodePath, codePath, manifestArray, isCoreApp);
+ @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp,
+ @Nullable ParsingPackageUtils.Callback callback) {
+ return new PackageImpl(
+ packageName, baseCodePath, codePath, manifestArray, isCoreApp, callback);
}
/**
@@ -453,7 +452,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
@NonNull
@VisibleForTesting
public static ParsingPackage forTesting(String packageName, String baseCodePath) {
- return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false);
+ return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false, null);
}
@NonNull
@@ -727,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) {
@@ -2694,12 +2678,16 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
private String mBaseAppDataCredentialProtectedDirForSystemUser;
private String mBaseAppDataDeviceProtectedDirForSystemUser;
+ ParsingPackageUtils.Callback mCallback;
+
@VisibleForTesting
public PackageImpl(@NonNull String packageName, @NonNull String baseApkPath,
- @NonNull String path, @Nullable TypedArray manifestArray, boolean isCoreApp) {
+ @NonNull String path, @Nullable TypedArray manifestArray, boolean isCoreApp,
+ @Nullable ParsingPackageUtils.Callback callback) {
this.packageName = TextUtils.safeIntern(packageName);
this.mBaseApkPath = baseApkPath;
this.mPath = path;
+ this.mCallback = callback;
if (manifestArray != null) {
versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0);
@@ -2750,9 +2738,11 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
private void assignDerivedFields2() {
- mBaseAppInfoFlags = PackageInfoUtils.appInfoFlags(this, null);
- mBaseAppInfoPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(this, null);
- mBaseAppInfoPrivateFlagsExt = PackageInfoUtils.appInfoPrivateFlagsExt(this, null);
+ mBaseAppInfoFlags = AppInfoUtils.appInfoFlags(this);
+ mBaseAppInfoPrivateFlags = AppInfoUtils.appInfoPrivateFlags(this);
+ mBaseAppInfoPrivateFlagsExt = AppInfoUtils.appInfoPrivateFlagsExt(this,
+ mCallback == null ? false :
+ mCallback.getHiddenApiWhitelistedApps().contains(this.packageName));
String baseAppDataDir = Environment.getDataDirectoryPath(getVolumeUuid()) + File.separator;
String systemUserSuffix = File.separator + UserHandle.USER_SYSTEM + File.separator;
mBaseAppDataCredentialProtectedDirForSystemUser = TextUtils.safeIntern(
@@ -3087,7 +3077,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
appInfo.primaryCpuAbi = primaryCpuAbi;
appInfo.secondaryCpuAbi = secondaryCpuAbi;
appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
- appInfo.seInfoUser = SELinuxUtil.COMPLETE_STR;
+ appInfo.seInfoUser = SEInfoUtil.COMPLETE_STR;
appInfo.uid = uid;
return appInfo;
}
diff --git a/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java b/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java
index d9625050d28c..a670c6d5aff4 100644
--- a/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java
+++ b/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.permission;
+package com.android.internal.pm.permission;
import android.Manifest;
import android.annotation.NonNull;
@@ -67,7 +67,7 @@ public class CompatibilityPermissionInfo {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -97,10 +97,10 @@ public class CompatibilityPermissionInfo {
}
@DataClass.Generated(
- time = 1627674427184L,
+ time = 1701338392152L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mName\nprivate final int mSdkVersion\npublic static final android.content.pm.permission.CompatibilityPermissionInfo[] COMPAT_PERMS\nclass CompatibilityPermissionInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genBuilder=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java",
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mName\nprivate final int mSdkVersion\npublic static final com.android.internal.pm.permission.CompatibilityPermissionInfo[] COMPAT_PERMS\nclass CompatibilityPermissionInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/com/android/internal/pm/pkg/SEInfoUtil.java b/core/java/com/android/internal/pm/pkg/SEInfoUtil.java
new file mode 100644
index 000000000000..a6988829ca92
--- /dev/null
+++ b/core/java/com/android/internal/pm/pkg/SEInfoUtil.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.pm.pkg;
+
+/**
+ * Utility methods that need to be used in application space.
+ * @hide
+ */
+public final class SEInfoUtil {
+
+ /** Append to existing seinfo label for instant apps @hide */
+ public static final String INSTANT_APP_STR = ":ephemeralapp";
+
+ /** Append to existing seinfo when modifications are complete @hide */
+ public static final String COMPLETE_STR = ":complete";
+}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java b/core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java
index 1964df0853fd..fd5f0f079da9 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java
@@ -14,19 +14,11 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.internal.pm.pkg.component.ParsedActivity;
-import com.android.internal.pm.pkg.component.ParsedComponent;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
-import com.android.internal.pm.pkg.component.ParsedPermission;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
-import com.android.internal.pm.pkg.component.ParsedProcess;
-import com.android.internal.pm.pkg.component.ParsedProvider;
-
/**
* Contains mutation methods so that code doesn't have to cast to the Impl. Meant to eventually
* be removed once all post-parsing mutation is moved to parsing.
diff --git a/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java b/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java
index 019ca1315af8..db08005c833e 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.AttrRes;
import android.annotation.NonNull;
@@ -29,14 +29,9 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.text.TextUtils;
-import com.android.internal.pm.pkg.component.ParsedComponent;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.PackageUserState;
-import com.android.server.pm.pkg.PackageUserStateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -173,16 +168,4 @@ public class ComponentParseUtils {
public static int getIcon(ParsedComponent component) {
return component.getIcon();
}
-
- public static boolean isMatch(PackageUserState state, boolean isSystem,
- boolean isPackageEnabled, ParsedMainComponent component, long flags) {
- return PackageUserStateUtils.isMatch(state, isSystem, isPackageEnabled,
- component.isEnabled(), component.isDirectBootAware(), component.getName(), flags);
- }
-
- public static boolean isEnabled(PackageUserState state, boolean isPackageEnabled,
- ParsedMainComponent parsedComponent, long flags) {
- return PackageUserStateUtils.isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
- parsedComponent.getName(), flags);
- }
}
diff --git a/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java b/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java
index dd54cfca6518..0b045919fb13 100644
--- a/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java
+++ b/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.content.pm.parsing.result.ParseInput;
@@ -27,7 +27,6 @@ import android.util.ArraySet;
import com.android.internal.R;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.SystemConfig;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -48,9 +47,8 @@ public class InstallConstraintsTagParser {
* @hide
*/
public static ParseResult<ParsingPackage> parseInstallConstraints(
- ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)
- throws XmlPullParserException, IOException {
- Set<String> allowlist = SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser,
+ Set<String> allowlist) throws XmlPullParserException, IOException {
if (!allowlist.contains(pkg.getPackageName())) {
return input.skip("install-constraints cannot be used by this package");
}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java
index f02790189cc0..2f977eea127d 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
@@ -22,8 +22,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VER
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForStringSet;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForStringSet;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,10 +36,9 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.ArraySet;
-import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import java.util.Collections;
import java.util.Locale;
@@ -380,7 +379,7 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -696,10 +695,10 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
}
@DataClass.Generated(
- time = 1669437519576L,
+ time = 1701338377709L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java",
- inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> mKnownActivityEmbeddingCerts\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\nprivate @android.annotation.Nullable java.lang.String mRequiredDisplayCategory\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.server.pm.pkg.component.ParsedActivityImpl> CREATOR\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.internal.pm.pkg.component.ParsedActivity)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts()\npublic void setKnownActivityEmbeddingCerts(java.util.Set<java.lang.String>)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java",
+ inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> mKnownActivityEmbeddingCerts\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\nprivate @android.annotation.Nullable java.lang.String mRequiredDisplayCategory\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedActivityImpl> CREATOR\npublic static @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.internal.pm.pkg.component.ParsedActivity)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts()\npublic void setKnownActivityEmbeddingCerts(java.util.Set<java.lang.String>)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java
index 64985bdfd54f..c3f7dab3c46a 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
+import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -48,11 +48,10 @@ import android.view.WindowManager;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java
index cfed19aa0934..27f7eee1a308 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedApexSystemService;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -60,7 +59,7 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService, Par
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -248,9 +247,9 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService, Par
};
@DataClass.Generated(
- time = 1643723578605L,
+ time = 1701710844088L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java",
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java",
inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nprivate int initOrder\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedApexSystemService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java
index d3fb29b8aa66..c69213f11f85 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.R;
import android.annotation.NonNull;
@@ -25,8 +25,6 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.text.TextUtils;
-import com.android.internal.pm.pkg.component.ParsedApexSystemService;
-
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java
index 62b994724346..e3bfb38802db 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.StringRes;
@@ -22,7 +22,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedAttribution;
import com.android.internal.util.DataClass;
import java.util.ArrayList;
@@ -60,7 +59,7 @@ public class ParsedAttributionImpl implements ParsedAttribution, Parcelable {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -207,10 +206,10 @@ public class ParsedAttributionImpl implements ParsedAttribution, Parcelable {
};
@DataClass.Generated(
- time = 1641431950829L,
+ time = 1701338881658L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java",
- inputSignatures = "static final int MAX_NUM_ATTRIBUTIONS\nprivate @android.annotation.NonNull java.lang.String tag\nprivate @android.annotation.StringRes int label\nprivate @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\nclass ParsedAttributionImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedAttribution, android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false, genSetters=true, genBuilder=false, genParcelable=true)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java",
+ inputSignatures = "static final int MAX_NUM_ATTRIBUTIONS\nprivate @android.annotation.NonNull java.lang.String tag\nprivate @android.annotation.StringRes int label\nprivate @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\nclass ParsedAttributionImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedAttribution, android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false, genSetters=true, genBuilder=false, genParcelable=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java
index 411220ae42e8..ee5c3204ccd1 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,7 +26,6 @@ import android.content.res.XmlResourceParser;
import android.util.ArraySet;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedAttribution;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
index 512e5c7023c7..7ee22f30ace0 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import static java.util.Collections.emptyMap;
@@ -32,12 +32,10 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedComponent;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.util.ArrayList;
import java.util.Collections;
@@ -200,7 +198,7 @@ public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedComponentImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -306,10 +304,10 @@ public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable
}
@DataClass.Generated(
- time = 1641414207885L,
+ time = 1701445673589L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedComponentImpl.java",
- inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String name\nprivate int icon\nprivate int labelRes\nprivate @android.annotation.Nullable java.lang.CharSequence nonLocalizedLabel\nprivate int logo\nprivate int banner\nprivate int descriptionRes\nprivate int flags\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String packageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"intent\") java.util.List<android.content.pm.parsing.component.ParsedIntentInfoImpl> intents\nprivate @android.annotation.Nullable android.content.ComponentName componentName\nprivate @android.annotation.Nullable android.os.Bundle metaData\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.PackageManager.Property> mProperties\n void addIntent(android.content.pm.parsing.component.ParsedIntentInfoImpl)\n void addProperty(android.content.pm.PackageManager.Property)\npublic android.content.pm.parsing.component.ParsedComponentImpl setName(java.lang.String)\npublic @android.annotation.CallSuper void setPackageName(java.lang.String)\npublic @java.lang.Override @android.annotation.NonNull android.content.ComponentName getComponentName()\npublic @android.annotation.NonNull @java.lang.Override android.os.Bundle getMetaData()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.parsing.component.ParsedIntentInfo> getIntents()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedComponentImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genConstructor=false, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java",
+ inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String name\nprivate int icon\nprivate int labelRes\nprivate @android.annotation.Nullable java.lang.CharSequence nonLocalizedLabel\nprivate int logo\nprivate int banner\nprivate int descriptionRes\nprivate int flags\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String packageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"intent\") java.util.List<com.android.internal.pm.pkg.component.ParsedIntentInfoImpl> intents\nprivate @android.annotation.Nullable android.content.ComponentName componentName\nprivate @android.annotation.Nullable android.os.Bundle metaData\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.PackageManager.Property> mProperties\npublic void addIntent(com.android.internal.pm.pkg.component.ParsedIntentInfoImpl)\npublic void addProperty(android.content.pm.PackageManager.Property)\npublic com.android.internal.pm.pkg.component.ParsedComponentImpl setName(java.lang.String)\npublic @android.annotation.CallSuper void setPackageName(java.lang.String)\npublic @java.lang.Override @android.annotation.NonNull android.content.ComponentName getComponentName()\npublic @android.annotation.NonNull @java.lang.Override android.os.Bundle getMetaData()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.internal.pm.pkg.component.ParsedIntentInfo> getIntents()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedComponentImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genConstructor=false, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java
index 9322cf0e90f6..9e2548b3bce3 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.PackageManager;
@@ -32,8 +32,8 @@ import android.util.TypedValue;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
/** @hide */
class ParsedComponentUtils {
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java
index 7bfad14d669a..07322e9dd912 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,7 +26,6 @@ import android.os.Parcelable;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -112,7 +111,7 @@ public class ParsedInstrumentationImpl extends ParsedComponentImpl implements
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -166,10 +165,10 @@ public class ParsedInstrumentationImpl extends ParsedComponentImpl implements
}
@DataClass.Generated(
- time = 1641431951575L,
+ time = 1701445763455L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java",
- inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetPackage\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetProcesses\nprivate boolean handleProfiling\nprivate boolean functionalTest\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedInstrumentationImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedInstrumentationImpl setTargetPackage(java.lang.String)\npublic android.content.pm.parsing.component.ParsedInstrumentationImpl setTargetProcesses(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedInstrumentationImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedInstrumentation, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java",
+ inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetPackage\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetProcesses\nprivate boolean handleProfiling\nprivate boolean functionalTest\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedInstrumentationImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedInstrumentationImpl setTargetPackage(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedInstrumentationImpl setTargetProcesses(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedInstrumentationImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedInstrumentation, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java
index a7116949b911..661c8b421fb4 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.parsing.result.ParseInput;
@@ -26,7 +26,6 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java
index ab9404310078..adb49e9fde6d 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -23,7 +23,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.util.DataClass;
/**
@@ -54,7 +53,7 @@ public class ParsedIntentInfoImpl implements ParsedIntentInfo, Parcelable {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -170,10 +169,10 @@ public class ParsedIntentInfoImpl implements ParsedIntentInfo, Parcelable {
};
@DataClass.Generated(
- time = 1641431952314L,
+ time = 1701445800363L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java",
- inputSignatures = "private boolean mHasDefault\nprivate int mLabelRes\nprivate @android.annotation.Nullable java.lang.CharSequence mNonLocalizedLabel\nprivate int mIcon\nprivate @android.annotation.NonNull android.content.IntentFilter mIntentFilter\nclass ParsedIntentInfoImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedIntentInfo, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false, genConstructor=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java",
+ inputSignatures = "private boolean mHasDefault\nprivate int mLabelRes\nprivate @android.annotation.Nullable java.lang.CharSequence mNonLocalizedLabel\nprivate int mIcon\nprivate @android.annotation.NonNull android.content.IntentFilter mIntentFilter\nclass ParsedIntentInfoImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedIntentInfo, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false, genConstructor=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
index e5e214d2292b..c6683cfc8331 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
import android.annotation.NonNull;
import android.content.Intent;
@@ -31,10 +31,9 @@ import android.util.Slog;
import android.util.TypedValue;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java
index f322eef8c3a3..bb8f565d2032 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -25,7 +25,6 @@ import android.os.Parcelable;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -133,7 +132,7 @@ public class ParsedMainComponentImpl extends ParsedComponentImpl implements Pars
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -227,10 +226,10 @@ public class ParsedMainComponentImpl extends ParsedComponentImpl implements Pars
}
@DataClass.Generated(
- time = 1641414540422L,
+ time = 1701447884766L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java",
- inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String processName\nprivate boolean directBootAware\nprivate boolean enabled\nprivate boolean exported\nprivate int order\nprivate @android.annotation.Nullable java.lang.String splitName\nprivate @android.annotation.Nullable java.lang.String[] attributionTags\npublic static final android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedMainComponentImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedMainComponentImpl setProcessName(java.lang.String)\npublic java.lang.String getClassName()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getAttributionTags()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedMainComponentImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedMainComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java",
+ inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String processName\nprivate boolean directBootAware\nprivate boolean enabled\nprivate boolean exported\nprivate int order\nprivate @android.annotation.Nullable java.lang.String splitName\nprivate @android.annotation.Nullable java.lang.String[] attributionTags\npublic static final android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedMainComponentImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedMainComponentImpl setProcessName(java.lang.String)\npublic java.lang.String getClassName()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getAttributionTags()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedMainComponentImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedMainComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java
index 8268f0fdfa3e..7e56180f72ce 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,10 +31,8 @@ import android.os.Build;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java
index afe37bc3274c..3622019f36b9 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
import com.android.internal.util.DataClass;
/**
@@ -75,7 +74,7 @@ public class ParsedPermissionGroupImpl extends ParsedComponentImpl implements
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -172,10 +171,10 @@ public class ParsedPermissionGroupImpl extends ParsedComponentImpl implements
};
@DataClass.Generated(
- time = 1642132854167L,
+ time = 1701445837884L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java",
- inputSignatures = "private int requestDetailRes\nprivate int backgroundRequestRes\nprivate int backgroundRequestDetailRes\nprivate int requestRes\nprivate int priority\npublic java.lang.String toString()\npublic @java.lang.Override @com.android.internal.util.DataClass.Generated.Member void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionGroupImpl extends com.android.server.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermissionGroup, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java",
+ inputSignatures = "private int requestDetailRes\nprivate int backgroundRequestRes\nprivate int backgroundRequestDetailRes\nprivate int requestRes\nprivate int priority\npublic java.lang.String toString()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionGroupImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermissionGroup, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java
index 69e33c8f281e..4dcce131168b 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -24,8 +24,6 @@ import android.text.TextUtils;
import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedPermission;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -148,7 +146,7 @@ public class ParsedPermissionImpl extends ParsedComponentImpl implements ParsedP
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -162,7 +160,7 @@ public class ParsedPermissionImpl extends ParsedComponentImpl implements ParsedP
int requestRes,
int protectionLevel,
boolean tree,
- @Nullable ParsedPermissionGroupImpl parsedPermissionGroup,
+ @Nullable ParsedPermissionGroup parsedPermissionGroup,
@Nullable Set<String> knownCerts) {
this.backgroundPermission = backgroundPermission;
this.group = group;
@@ -237,10 +235,10 @@ public class ParsedPermissionImpl extends ParsedComponentImpl implements ParsedP
}
@DataClass.Generated(
- time = 1641414649731L,
+ time = 1701445829812L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java",
- inputSignatures = "private static com.android.internal.util.Parcelling.BuiltIn.ForStringSet sForStringSet\nprivate @android.annotation.Nullable java.lang.String backgroundPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String group\nprivate int requestRes\nprivate int protectionLevel\nprivate boolean tree\nprivate @android.annotation.Nullable android.content.pm.parsing.component.ParsedPermissionGroupImpl parsedPermissionGroup\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> knownCerts\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedPermissionImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedPermissionGroup getParsedPermissionGroup()\npublic android.content.pm.parsing.component.ParsedPermissionImpl setGroup(java.lang.String)\nprotected void setKnownCert(java.lang.String)\nprotected void setKnownCerts(java.lang.String[])\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownCerts()\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java",
+ inputSignatures = "private static final com.android.internal.util.Parcelling.BuiltIn.ForStringSet sForStringSet\nprivate @android.annotation.Nullable java.lang.String backgroundPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String group\nprivate int requestRes\nprivate int protectionLevel\nprivate boolean tree\nprivate @android.annotation.Nullable com.android.internal.pm.pkg.component.ParsedPermissionGroup parsedPermissionGroup\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> knownCerts\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedPermissionImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedPermissionGroup getParsedPermissionGroup()\npublic com.android.internal.pm.pkg.component.ParsedPermissionImpl setGroup(java.lang.String)\nprotected void setKnownCert(java.lang.String)\nprotected void setKnownCerts(java.lang.String[])\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownCerts()\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java
index 4b45d3742a2a..5651c1ca247f 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.PermissionInfo;
@@ -31,10 +31,8 @@ import android.util.EventLog;
import android.util.Slog;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedPermission;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java
index 40e3670b9261..212fb867e7df 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import static java.util.Collections.emptySet;
@@ -25,7 +25,6 @@ import android.os.Parcelable;
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -98,7 +97,7 @@ public class ParsedProcessImpl implements ParsedProcess, Parcelable {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcessImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -304,10 +303,10 @@ public class ParsedProcessImpl implements ParsedProcess, Parcelable {
};
@DataClass.Generated(
- time = 1641431953775L,
+ time = 1701445656489L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcessImpl.java",
- inputSignatures = "private @android.annotation.NonNull java.lang.String name\nprivate @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.String> appClassNamesByPackage\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprivate @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nprivate @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\nprivate @android.content.pm.ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\npublic void putAppClassNameForPackage(java.lang.String,java.lang.String)\nclass ParsedProcessImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedProcess, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java",
+ inputSignatures = "private @android.annotation.NonNull java.lang.String name\nprivate @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.String> appClassNamesByPackage\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprivate @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nprivate @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\nprivate @android.content.pm.ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized\npublic void addStateFrom(com.android.internal.pm.pkg.component.ParsedProcess)\npublic void putAppClassNameForPackage(java.lang.String,java.lang.String)\nclass ParsedProcessImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedProcess, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java
index a84954950f44..3b2056e7892e 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
@@ -27,11 +27,10 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.XmlUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java
index 81a3c17e2bb4..987fd4158418 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,7 +28,6 @@ import android.os.PatternMatcher;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -302,7 +301,7 @@ public class ParsedProviderImpl extends ParsedMainComponentImpl implements Parse
time = 1642560323360L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java",
- inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String authority\nprivate boolean syncable\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String readPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String writePermission\nprivate boolean grantUriPermissions\nprivate boolean forceUriPermissions\nprivate boolean multiProcess\nprivate int initOrder\nprivate @android.annotation.NonNull java.util.List<android.os.PatternMatcher> uriPermissionPatterns\nprivate @android.annotation.NonNull java.util.List<android.content.pm.PathPermission> pathPermissions\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.server.pm.pkg.component.ParsedProviderImpl> CREATOR\npublic com.android.server.pm.pkg.component.ParsedProviderImpl setReadPermission(java.lang.String)\npublic com.android.server.pm.pkg.component.ParsedProviderImpl setWritePermission(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedProviderImpl addUriPermissionPattern(android.os.PatternMatcher)\npublic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedProviderImpl addPathPermission(android.content.pm.PathPermission)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedProviderImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedProvider, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
+ inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String authority\nprivate boolean syncable\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String readPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String writePermission\nprivate boolean grantUriPermissions\nprivate boolean forceUriPermissions\nprivate boolean multiProcess\nprivate int initOrder\nprivate @android.annotation.NonNull java.util.List<android.os.PatternMatcher> uriPermissionPatterns\nprivate @android.annotation.NonNull java.util.List<android.content.pm.PathPermission> pathPermissions\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedProviderImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedProviderImpl setReadPermission(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedProviderImpl setWritePermission(java.lang.String)\npublic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedProviderImpl addUriPermissionPattern(android.os.PatternMatcher)\npublic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedProviderImpl addPathPermission(android.content.pm.PathPermission)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedProviderImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedProvider, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
index 0b28a1214072..5d82d0469d56 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
-import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
+import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag;
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,9 +34,8 @@ import android.os.PatternMatcher;
import android.util.Slog;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java
index ca8c45d1383c..f4662d803296 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,8 +26,6 @@ import android.os.Parcelable;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
-import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -107,7 +105,7 @@ public class ParsedServiceImpl extends ParsedMainComponentImpl implements Parsed
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedServiceImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -141,10 +139,10 @@ public class ParsedServiceImpl extends ParsedMainComponentImpl implements Parsed
}
@DataClass.Generated(
- time = 1641431954479L,
+ time = 1701445638370L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedServiceImpl.java",
- inputSignatures = "private int foregroundServiceType\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedServiceImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedMainComponent setPermission(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedServiceImpl extends android.content.pm.parsing.component.ParsedMainComponentImpl implements [android.content.pm.parsing.component.ParsedService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java",
+ inputSignatures = "private int foregroundServiceType\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedServiceImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedMainComponent setPermission(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedServiceImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
index 171ef594f6fd..a1dd19a3bc90 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
+import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -32,9 +32,8 @@ import android.content.res.XmlResourceParser;
import android.os.Build;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java
index 78377a836651..fd131dfd00c7 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedUsesPermission;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -51,7 +50,7 @@ public class ParsedUsesPermissionImpl implements ParsedUsesPermission, Parcelabl
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -158,10 +157,10 @@ public class ParsedUsesPermissionImpl implements ParsedUsesPermission, Parcelabl
};
@DataClass.Generated(
- time = 1641431955242L,
+ time = 1701445626268L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java",
- inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @android.content.pm.parsing.component.ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags\nclass ParsedUsesPermissionImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedUsesPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java",
+ inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.pm.pkg.component.ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags\nclass ParsedUsesPermissionImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedUsesPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index aa0fb2734382..dbe4fba5dfdb 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.parsing;
+package com.android.internal.pm.pkg.parsing;
import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -30,7 +30,7 @@ import static android.os.Build.VERSION_CODES.DONUT;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
import android.annotation.AnyRes;
import android.annotation.CheckResult;
@@ -57,7 +57,6 @@ import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseInput.DeferredError;
import android.content.pm.parsing.result.ParseResult;
-import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.Configuration;
@@ -90,43 +89,40 @@ import android.util.apk.ApkSignatureVerifier;
import com.android.internal.R;
import com.android.internal.os.ClassLoaderFactory;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.permission.CompatibilityPermissionInfo;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
+import com.android.internal.pm.pkg.component.ComponentParseUtils;
+import com.android.internal.pm.pkg.component.InstallConstraintsTagParser;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
+import com.android.internal.pm.pkg.component.ParsedActivityUtils;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
+import com.android.internal.pm.pkg.component.ParsedApexSystemServiceUtils;
import com.android.internal.pm.pkg.component.ParsedAttribution;
+import com.android.internal.pm.pkg.component.ParsedAttributionUtils;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationUtils;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoUtils;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.pm.pkg.component.ParsedProcess;
+import com.android.internal.pm.pkg.component.ParsedProcessUtils;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderUtils;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.component.ParsedServiceUtils;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
-import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
+import com.android.internal.pm.split.DefaultSplitAssetLoader;
+import com.android.internal.pm.split.SplitAssetDependencyLoader;
+import com.android.internal.pm.split.SplitAssetLoader;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
-import com.android.server.pm.SharedUidMigration;
-import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.permission.CompatibilityPermissionInfo;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ComponentParseUtils;
-import com.android.server.pm.pkg.component.InstallConstraintsTagParser;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedActivityUtils;
-import com.android.server.pm.pkg.component.ParsedApexSystemServiceUtils;
-import com.android.server.pm.pkg.component.ParsedAttributionUtils;
-import com.android.server.pm.pkg.component.ParsedInstrumentationUtils;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
-import com.android.server.pm.pkg.component.ParsedIntentInfoUtils;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
-import com.android.server.pm.pkg.component.ParsedProcessUtils;
-import com.android.server.pm.pkg.component.ParsedProviderUtils;
-import com.android.server.pm.pkg.component.ParsedServiceUtils;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
-import com.android.server.pm.split.DefaultSplitAssetLoader;
-import com.android.server.pm.split.SplitAssetDependencyLoader;
-import com.android.server.pm.split.SplitAssetLoader;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -267,18 +263,6 @@ public class ParsingPackageUtils {
public @interface ParseFlags {}
/**
- * @see #parseDefault(ParseInput, File, int, List, boolean)
- */
- @NonNull
- public static ParseResult<ParsedPackage> parseDefaultOneTime(File file,
- @ParseFlags int parseFlags,
- @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
- boolean collectCertificates) {
- ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
- return parseDefault(input, file, parseFlags, splitPermissions, collectCertificates);
- }
-
- /**
* For cases outside of PackageManagerService when an APK needs to be parsed as a one-off
* request, without caching the input object and without querying the internal system state for
* feature support.
@@ -287,30 +271,10 @@ public class ParsingPackageUtils {
public static ParseResult<ParsedPackage> parseDefault(ParseInput input, File file,
@ParseFlags int parseFlags,
@NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
- boolean collectCertificates) {
- ParseResult<ParsedPackage> result;
+ boolean collectCertificates, Callback callback) {
ParsingPackageUtils parser = new ParsingPackageUtils(null /*separateProcesses*/,
- null /*displayMetrics*/, splitPermissions, new Callback() {
- @Override
- public boolean hasFeature(String feature) {
- // Assume the device doesn't support anything. This will affect permission
- // parsing and will force <uses-permission/> declarations to include all
- // requiredNotFeature permissions and exclude all requiredFeature
- // permissions. This mirrors the old behavior.
- return false;
- }
-
- @Override
- public ParsingPackage startParsingPackage(
- @NonNull String packageName,
- @NonNull String baseApkPath,
- @NonNull String path,
- @NonNull TypedArray manifestArray, boolean isCoreApp) {
- return PackageImpl.forParsing(packageName, baseApkPath, path, manifestArray,
- isCoreApp);
- }
- });
+ null /*displayMetrics*/, splitPermissions, callback);
var parseResult = parser.parsePackage(input, file, parseFlags);
if (parseResult.isError()) {
return input.error(parseResult);
@@ -1146,7 +1110,8 @@ public class ParsingPackageUtils {
case TAG_RESTRICT_UPDATE:
return parseRestrictUpdateHash(flags, input, pkg, res, parser);
case TAG_INSTALL_CONSTRAINTS:
- return parseInstallConstraints(input, pkg, res, parser);
+ return parseInstallConstraints(input, pkg, res, parser,
+ mCallback.getInstallConstraintsAllowlist());
case TAG_QUERIES:
return parseQueries(input, pkg, res, parser);
default:
@@ -1172,7 +1137,7 @@ public class ParsingPackageUtils {
}
boolean leaving = false;
- if (!SharedUidMigration.isDisabled()) {
+ if (PackageManager.ENABLE_SHARED_UID_MIGRATION) {
int max = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
leaving = (max != 0) && (max < Build.VERSION.RESOURCES_SDK_INT);
}
@@ -1858,10 +1823,11 @@ public class ParsingPackageUtils {
return input.success(pkg);
}
- private static ParseResult<ParsingPackage> parseInstallConstraints(
- ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)
+ private static ParseResult<ParsingPackage> parseInstallConstraints(ParseInput input,
+ ParsingPackage pkg, Resources res, XmlResourceParser parser, Set<String> allowlist)
throws IOException, XmlPullParserException {
- return InstallConstraintsTagParser.parseInstallConstraints(input, pkg, res, parser);
+ return InstallConstraintsTagParser.parseInstallConstraints(
+ input, pkg, res, parser, allowlist);
}
private static ParseResult<ParsingPackage> parseQueries(ParseInput input, ParsingPackage pkg,
@@ -3485,5 +3451,9 @@ public class ParsingPackageUtils {
ParsingPackage startParsingPackage(@NonNull String packageName,
@NonNull String baseApkPath, @NonNull String path,
@NonNull TypedArray manifestArray, boolean isCoreApp);
+
+ @NonNull Set<String> getHiddenApiWhitelistedApps();
+
+ @NonNull Set<String> getInstallConstraintsAllowlist();
}
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java
index 1d159554e8a7..26822c649db7 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java
@@ -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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.parsing;
+package com.android.internal.pm.pkg.parsing;
-import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,10 +31,9 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
-import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
import com.android.internal.util.Parcelling;
import com.android.internal.util.XmlUtils;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java b/core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java
index 0bb969f488fe..50c62437b192 100644
--- a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.pm.split;
+package com.android.internal.pm.split;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
@@ -21,9 +21,9 @@ import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.os.Build;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java b/core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java
index 56d92fbc95a2..c166cdcf9451 100644
--- a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.pm.split;
+package com.android.internal.pm.split;
import android.annotation.NonNull;
import android.content.pm.parsing.ApkLiteParseUtils;
@@ -24,8 +24,8 @@ import android.content.res.AssetManager;
import android.os.Build;
import android.util.SparseArray;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/pm/split/SplitAssetLoader.java b/core/java/com/android/internal/pm/split/SplitAssetLoader.java
index 845015916e60..c7c409d826ba 100644
--- a/services/core/java/com/android/server/pm/split/SplitAssetLoader.java
+++ b/core/java/com/android/internal/pm/split/SplitAssetLoader.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.pm.split;
+package com.android.internal.pm.split;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
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/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 28fd2b488426..bf8e6135fd01 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -897,13 +897,26 @@ public class LockPatternUtils {
}
/**
- * Returns true if {@code userHandle} is a managed profile with separate challenge.
+ * Returns true if {@code userHandle} is a profile with separate challenge.
+ * <p>
+ * Returns false if {@code userHandle} is a profile with unified challenge, a profile whose
+ * credential is not shareable with its parent, or a non-profile user.
*/
public boolean isSeparateProfileChallengeEnabled(int userHandle) {
return isCredentialSharableWithParent(userHandle) && hasSeparateChallenge(userHandle);
}
/**
+ * Returns true if {@code userHandle} is a profile with unified challenge.
+ * <p>
+ * Returns false if {@code userHandle} is a profile with separate challenge, a profile whose
+ * credential is not shareable with its parent, or a non-profile user.
+ */
+ public boolean isProfileWithUnifiedChallenge(int userHandle) {
+ return isCredentialSharableWithParent(userHandle) && !hasSeparateChallenge(userHandle);
+ }
+
+ /**
* Returns true if {@code userHandle} is a managed profile with unified challenge.
*/
public boolean isManagedProfileWithUnifiedChallenge(int userHandle) {
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index c88763ce6c97..18d5f6db6ac9 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -134,12 +134,12 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
}
/**
- * Creates a LockscreenCredential object representing a managed password for profile with
- * unified challenge. This credentiall will have type {@code CREDENTIAL_TYPE_PASSWORD} for now.
- * TODO: consider add a new credential type for this. This can then supersede the
- * isLockTiedToParent argument in various places in LSS.
+ * Creates a LockscreenCredential object representing the system-generated, system-managed
+ * password for a profile with unified challenge. This credential has type {@code
+ * CREDENTIAL_TYPE_PASSWORD} for now. TODO: consider add a new credential type for this. This
+ * can then supersede the isLockTiedToParent argument in various places in LSS.
*/
- public static LockscreenCredential createManagedPassword(@NonNull byte[] password) {
+ public static LockscreenCredential createUnifiedProfilePassword(@NonNull byte[] password) {
return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD,
Arrays.copyOf(password, password.length), /* hasInvalidChars= */ false);
}
diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java
index f86595f1ea7b..adb0c6959f12 100644
--- a/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -58,6 +58,7 @@ import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import java.security.PublicKey;
import java.util.List;
@@ -690,7 +691,7 @@ public interface AndroidPackage {
/**
* The names of packages to adopt ownership of permissions from, parsed under {@link
- * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
+ * ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
*
* @see R.styleable#AndroidManifestOriginalPackage_name
* @hide
@@ -795,7 +796,7 @@ public interface AndroidPackage {
/**
* For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
- * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_KEY_SETS}.
+ * ParsingPackageUtils#TAG_KEY_SETS}.
*
* @see R.styleable#AndroidManifestKeySet
* @see R.styleable#AndroidManifestPublicKey
@@ -1266,7 +1267,7 @@ public interface AndroidPackage {
/**
* For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
- * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_KEY_SETS}.
+ * ParsingPackageUtils#TAG_KEY_SETS}.
*
* @see R.styleable#AndroidManifestUpgradeKeySet
* @hide
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/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 87ab4969040e..54c4cd50a902 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -63,6 +63,7 @@ class NativeCommandBuffer {
std::optional<std::pair<char*, char*>> readLine(FailFn fail_fn) {
char* result = mBuffer + mNext;
while (true) {
+ // We have scanned up to, but not including mNext for this line's newline.
if (mNext == mEnd) {
if (mEnd == MAX_COMMAND_BYTES) {
return {};
@@ -89,7 +90,7 @@ class NativeCommandBuffer {
} else {
mNext = nl - mBuffer + 1;
if (--mLinesLeft < 0) {
- fail_fn("ZygoteCommandBuffer.readLine attempted to read past mEnd of command");
+ fail_fn("ZygoteCommandBuffer.readLine attempted to read past end of command");
}
return std::make_pair(result, nl);
}
@@ -125,8 +126,8 @@ class NativeCommandBuffer {
mEnd += lineLen + 1;
}
- // Clear mBuffer, start reading new command, return the number of arguments, leaving mBuffer
- // positioned at the beginning of first argument. Return 0 on EOF.
+ // Start reading new command, return the number of arguments, leaving mBuffer positioned at the
+ // beginning of first argument. Return 0 on EOF.
template<class FailFn>
int getCount(FailFn fail_fn) {
mLinesLeft = 1;
@@ -451,11 +452,14 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
(CREATE_ERROR("Write unexpectedly returned short: %d < 5", res));
}
}
- // Clear buffer and get count from next command.
- n_buffer->clear();
for (;;) {
+ // Clear buffer and get count from next command.
+ n_buffer->clear();
// Poll isn't strictly necessary for now. But without it, disconnect is hard to detect.
int poll_res = TEMP_FAILURE_RETRY(poll(fd_structs, 2, -1 /* infinite timeout */));
+ if (poll_res < 0) {
+ fail_fn_z(CREATE_ERROR("Poll failed: %d: %s", errno, strerror(errno)));
+ }
if ((fd_structs[SESSION_IDX].revents & POLLIN) != 0) {
if (n_buffer->getCount(fail_fn_z) != 0) {
break;
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/strings.xml b/core/res/res/values/strings.xml
index 1f6ac80a133c..4596ca74bf8f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5252,6 +5252,8 @@
<!-- Zen mode - name of default automatic calendar time-based rule that is triggered every night (when sleeping). [CHAR LIMIT=40] -->
<string name="zen_mode_default_every_night_name">Sleeping</string>
+ <!-- Zen mode - Trigger description of the rule, indicating which app owns it. [CHAR_LIMIT=100] -->
+ <string name="zen_mode_implicit_trigger_description">Managed by <xliff:g id="app_name">%1$s</xliff:g></string>
<!-- Zen mode - Condition summary when a rule is activated due to a call to setInterruptionFilter(). [CHAR_LIMIT=NONE] -->
<string name="zen_mode_implicit_activated">On</string>
<!-- Zen mode - Condition summary when a rule is deactivated due to a call to setInterruptionFilter(). [CHAR_LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5791ddb8addf..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" />
@@ -2586,6 +2587,7 @@
<java-symbol type="string" name="zen_mode_default_weekends_name" />
<java-symbol type="string" name="zen_mode_default_events_name" />
<java-symbol type="string" name="zen_mode_default_every_night_name" />
+ <java-symbol type="string" name="zen_mode_implicit_trigger_description" />
<java-symbol type="string" name="zen_mode_implicit_activated" />
<java-symbol type="string" name="zen_mode_implicit_deactivated" />
<java-symbol type="string" name="display_rotation_camera_compat_toast_after_rotation" />
diff --git a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
index ba2ea88e8e01..1925588e8904 100644
--- a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
+++ b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
@@ -19,15 +19,20 @@ package android.app;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertThrows;
+
import android.content.ComponentName;
import android.net.Uri;
import android.os.Parcel;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.google.common.base.Strings;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,6 +43,9 @@ import java.lang.reflect.Field;
public class AutomaticZenRuleTest {
private static final String CLASS = "android.app.AutomaticZenRule";
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Test
public void testLongFields_inConstructor() {
String longString = Strings.repeat("A", 65536);
@@ -100,6 +108,7 @@ public class AutomaticZenRuleTest {
}
@Test
+ @EnableFlags(Flags.FLAG_MODES_API)
public void testLongInputsFromParcel() {
// Create a rule with long fields, set directly via reflection so that we can confirm that
// a rule with too-long fields that comes in via a parcel has its fields truncated directly.
@@ -152,6 +161,69 @@ public class AutomaticZenRuleTest {
fromParcel.getOwner().getPackageName().length());
assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
fromParcel.getOwner().getClassName().length());
- assertEquals(AutomaticZenRule.MAX_DESC_LENGTH, rule.getTriggerDescription().length());
+ assertEquals(AutomaticZenRule.MAX_DESC_LENGTH, fromParcel.getTriggerDescription().length());
+ }
+
+ @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)
+ .build();
+ rule.validate(); // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_builderWithoutType_succeeds() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
+ rule.validate(); // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_constructorWithoutType_succeeds() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule("rule", new ComponentName("pkg", "cps"),
+ new ComponentName("pkg", "activity"), Uri.parse("condition"), null,
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ rule.validate(); // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_invalidType_throws() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
+
+ // Set the field via reflection.
+ Field typeField = AutomaticZenRule.class.getDeclaredField("mType");
+ typeField.setAccessible(true);
+ typeField.set(rule, 100);
+
+ assertThrows(IllegalArgumentException.class, rule::validate);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void setType_invalidType_throws() {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
+
+ assertThrows(IllegalArgumentException.class, () -> rule.setType(100));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void setTypeBuilder_invalidType_throws() {
+ AutomaticZenRule.Builder builder = new AutomaticZenRule.Builder("rule", Uri.parse("uri"));
+
+ assertThrows(IllegalArgumentException.class, () -> builder.setType(100));
}
}
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index 8c231de5598f..e7b5dff60110 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -197,7 +197,6 @@ public class BundleTest {
}
@Test
- @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void kindofEquals_bothParcelled_same() {
Bundle bundle1 = new Bundle();
bundle1.putString("StringKey", "S");
@@ -215,7 +214,6 @@ public class BundleTest {
}
@Test
- @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void kindofEquals_bothParcelled_different() {
Bundle bundle1 = new Bundle();
bundle1.putString("StringKey", "S");
@@ -247,7 +245,6 @@ public class BundleTest {
}
@Test
- @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void kindofEquals_lazyValues() {
Parcelable p1 = new CustomParcelable(13, "Tiramisu");
Parcelable p2 = new CustomParcelable(13, "Tiramisu");
@@ -281,7 +278,6 @@ public class BundleTest {
}
@Test
- @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void kindofEquals_lazyValuesWithIdenticalParcels_returnsTrue() {
Parcelable p1 = new CustomParcelable(13, "Tiramisu");
Parcelable p2 = new CustomParcelable(13, "Tiramisu");
diff --git a/core/tests/coretests/src/android/os/MessageQueueTest.java b/core/tests/coretests/src/android/os/MessageQueueTest.java
index 8cd6773936ef..851e61259241 100644
--- a/core/tests/coretests/src/android/os/MessageQueueTest.java
+++ b/core/tests/coretests/src/android/os/MessageQueueTest.java
@@ -16,6 +16,7 @@
package android.os;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.MediumTest;
@@ -153,6 +154,7 @@ public class MessageQueueTest {
@Test
@MediumTest
+ @IgnoreUnderRavenwood(reason = "Flaky test, b/315872700")
public void testFieldIntegrity() throws Exception {
TestHandlerThread tester = new TestFieldIntegrityHandler() {
diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java
index 5bbd2219e2f0..26f6d696768a 100644
--- a/core/tests/coretests/src/android/os/ParcelTest.java
+++ b/core/tests/coretests/src/android/os/ParcelTest.java
@@ -132,7 +132,6 @@ public class ParcelTest {
}
@Test
- @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testCompareDataInRange_whenSameData() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
@@ -169,7 +168,6 @@ public class ParcelTest {
}
@Test
- @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testCompareDataInRange_whenDifferentData() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
@@ -186,7 +184,6 @@ public class ParcelTest {
}
@Test
- @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testCompareDataInRange_whenLimitOutOfBounds_throws() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
@@ -213,7 +210,6 @@ public class ParcelTest {
}
@Test
- @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testCompareDataInRange_whenLengthZero() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
@@ -232,7 +228,6 @@ public class ParcelTest {
}
@Test
- @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testCompareDataInRange_whenNegativeLength_throws() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
@@ -248,7 +243,6 @@ public class ParcelTest {
}
@Test
- @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testCompareDataInRange_whenNegativeOffset_throws() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
diff --git a/core/tests/coretests/src/android/service/notification/ConditionTest.java b/core/tests/coretests/src/android/service/notification/ConditionTest.java
index 612562eb22dc..e94273e1ada7 100644
--- a/core/tests/coretests/src/android/service/notification/ConditionTest.java
+++ b/core/tests/coretests/src/android/service/notification/ConditionTest.java
@@ -21,9 +21,12 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertThrows;
+
import android.app.Flags;
import android.net.Uri;
import android.os.Parcel;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -36,6 +39,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -194,4 +198,59 @@ public class ConditionTest {
Condition fromParcel = new Condition(parcel);
assertThat(fromParcel).isEqualTo(cond);
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_unspecifiedSource_succeeds() {
+ new Condition(Uri.parse("id"), "Summary", Condition.STATE_TRUE);
+ // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_validSource_succeeds() {
+ new Condition(Uri.parse("id"), "Summary", Condition.STATE_TRUE, Condition.SOURCE_CONTEXT);
+ // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_invalidSource_throws() {
+ assertThrows(IllegalArgumentException.class,
+ () -> new Condition(Uri.parse("uri"), "Summary", Condition.STATE_TRUE, 1000));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_parcelWithInvalidSource_throws() {
+ Condition original = new Condition(Uri.parse("condition"), "Summary", Condition.STATE_TRUE,
+ Condition.SOURCE_SCHEDULE);
+ Parcel parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+
+ // Tweak the parcel to contain and invalid source value.
+ parcel.setDataPosition(parcel.dataPosition() - 8); // going back two int fields.
+ parcel.writeInt(100);
+ parcel.setDataPosition(0);
+
+ assertThrows(IllegalArgumentException.class, () -> new Condition(parcel));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_invalidSource_throws() throws Exception {
+ Condition condition = new Condition(Uri.parse("condition"), "Summary", Condition.STATE_TRUE,
+ Condition.SOURCE_SCHEDULE);
+
+ Field typeField = Condition.class.getDeclaredField("source");
+
+ // Reflection on reflection (ugh) to make a final field non-final
+ Field fieldAccessFlagsField = Field.class.getDeclaredField("accessFlags");
+ fieldAccessFlagsField.setAccessible(true);
+ fieldAccessFlagsField.setInt(typeField, typeField.getModifiers() & ~Modifier.FINAL);
+
+ typeField.setInt(condition, 30);
+
+ assertThrows(IllegalArgumentException.class, condition::validate);
+ }
}
diff --git a/core/tests/coretests/src/android/util/SparseSetArrayTest.java b/core/tests/coretests/src/android/util/SparseSetArrayTest.java
index 1df1090e0343..1c72185ea93c 100644
--- a/core/tests/coretests/src/android/util/SparseSetArrayTest.java
+++ b/core/tests/coretests/src/android/util/SparseSetArrayTest.java
@@ -37,6 +37,7 @@ public class SparseSetArrayTest {
public final RavenwoodRule mRavenwood = new RavenwoodRule();
@Test
+ @IgnoreUnderRavenwood(reason = "Flaky test, b/315872700")
public void testAddAll() {
final SparseSetArray<Integer> sparseSetArray = new SparseSetArray<>();
diff --git a/core/tests/utiltests/src/android/util/TimeUtilsTest.java b/core/tests/utiltests/src/android/util/TimeUtilsTest.java
index e8246c83e086..ac659e1bc593 100644
--- a/core/tests/utiltests/src/android/util/TimeUtilsTest.java
+++ b/core/tests/utiltests/src/android/util/TimeUtilsTest.java
@@ -18,8 +18,12 @@ package android.util;
import static org.junit.Assert.assertEquals;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,6 +33,9 @@ import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
public class TimeUtilsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
public static final long SECOND_IN_MILLIS = 1000;
public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
@@ -78,6 +85,7 @@ public class TimeUtilsTest {
}
@Test
+ @IgnoreUnderRavenwood(reason = "Flaky test, b/315872700")
public void testDumpTime() {
assertEquals("2023-01-01 00:00:00.000", runWithPrintWriter((pw) -> {
TimeUtils.dumpTime(pw, 1672556400000L);
@@ -91,6 +99,7 @@ public class TimeUtilsTest {
}
@Test
+ @IgnoreUnderRavenwood(reason = "Flaky test, b/315872700")
public void testFormatForLogging() {
assertEquals("unknown", TimeUtils.formatForLogging(0));
assertEquals("unknown", TimeUtils.formatForLogging(-1));
@@ -99,6 +108,7 @@ public class TimeUtilsTest {
}
@Test
+ @IgnoreUnderRavenwood(reason = "Flaky test, b/315872700")
public void testLogTimeOfDay() {
assertEquals("01-01 00:00:00.000", TimeUtils.logTimeOfDay(1672556400000L));
}
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/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
index 15d14e87fcf6..b315f94b5d00 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
@@ -241,7 +241,7 @@ public class WindowAreaComponentImpl implements WindowAreaComponent,
for (int i = 0; i < displays.length; i++) {
DisplayAddress.Physical address =
(DisplayAddress.Physical) displays[i].getAddress();
- if (mRearDisplayAddress == address.getPhysicalDisplayId()) {
+ if (address != null && mRearDisplayAddress == address.getPhysicalDisplayId()) {
rearDisplayMetrics = new DisplayMetrics();
final Display rearDisplay = displays[i];
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/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 0f0fbd9cc12f..f801b0d01084 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -83,6 +83,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
private int mStartPos;
private GestureDetector mDoubleTapDetector;
private boolean mInteractive;
+ private boolean mHideHandle;
private boolean mSetTouchRegion = true;
private int mLastDraggingPosition;
private int mHandleRegionWidth;
@@ -211,11 +212,8 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
}
/** Sets up essential dependencies of the divider bar. */
- public void setup(
- SplitLayout layout,
- SplitWindowManager splitWindowManager,
- SurfaceControlViewHost viewHost,
- InsetsState insetsState) {
+ public void setup(SplitLayout layout, SplitWindowManager splitWindowManager,
+ SurfaceControlViewHost viewHost, InsetsState insetsState) {
mSplitLayout = layout;
mSplitWindowManager = splitWindowManager;
mViewHost = viewHost;
@@ -277,6 +275,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
R.dimen.docked_stack_divider_lift_elevation);
mDoubleTapDetector = new GestureDetector(getContext(), new DoubleTapListener());
mInteractive = true;
+ mHideHandle = false;
setOnTouchListener(this);
mHandle.setAccessibilityDelegate(mHandleDelegate);
setWillNotDraw(false);
@@ -469,10 +468,11 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
void setInteractive(boolean interactive, boolean hideHandle, String from) {
if (interactive == mInteractive) return;
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
- "Set divider bar %s from %s", interactive ? "interactive" : "non-interactive",
- from);
+ "Set divider bar %s hide handle=%b from %s",
+ interactive ? "interactive" : "non-interactive", hideHandle, from);
mInteractive = interactive;
- if (!mInteractive && hideHandle && mMoving) {
+ mHideHandle = hideHandle;
+ if (!mInteractive && mHideHandle && mMoving) {
final int position = mSplitLayout.getDividePosition();
mSplitLayout.flingDividePosition(
mLastDraggingPosition,
@@ -482,7 +482,15 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
mMoving = false;
}
releaseTouching();
- mHandle.setVisibility(!mInteractive && hideHandle ? View.INVISIBLE : View.VISIBLE);
+ mHandle.setVisibility(!mInteractive && mHideHandle ? View.INVISIBLE : View.VISIBLE);
+ }
+
+ boolean isInteractive() {
+ return mInteractive;
+ }
+
+ boolean isHandleHidden() {
+ return mHideHandle;
}
private class DoubleTapListener extends GestureDetector.SimpleOnGestureListener {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index b699533374df..53caddb52f23 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -59,6 +59,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
@@ -70,6 +71,7 @@ import com.android.wm.shell.common.InteractionJankMonitorUtils;
import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -420,7 +422,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public void init() {
if (mInitialized) return;
mInitialized = true;
- mSplitWindowManager.init(this, mInsetsState);
+ mSplitWindowManager.init(this, mInsetsState, false /* isRestoring */);
mDisplayImeController.addPositionProcessor(mImePositionProcessor);
}
@@ -442,14 +444,19 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
/** Releases and re-inflates {@link DividerView} on the root surface. */
- public void update(SurfaceControl.Transaction t) {
+ public void update(SurfaceControl.Transaction t, boolean resetImePosition) {
if (!mInitialized) {
init();
return;
}
mSplitWindowManager.release(t);
- mImePositionProcessor.reset();
- mSplitWindowManager.init(this, mInsetsState);
+ if (resetImePosition) {
+ mImePositionProcessor.reset();
+ }
+ mSplitWindowManager.init(this, mInsetsState, true /* isRestoring */);
+ // Update the surface positions again after recreating the divider in case nothing else
+ // triggers it
+ mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
}
@Override
@@ -868,6 +875,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
pw.println(prefix + TAG + ":");
pw.println(innerPrefix + "mAllowLeftRightSplitInPortrait=" + mAllowLeftRightSplitInPortrait);
pw.println(innerPrefix + "mIsLeftRightSplit=" + mIsLeftRightSplit);
+ pw.println(innerPrefix + "mFreezeDividerWindow=" + mFreezeDividerWindow);
+ pw.println(innerPrefix + "mDimNonImeSide=" + mDimNonImeSide);
+ pw.println(innerPrefix + "mDividerPosition=" + mDividerPosition);
pw.println(innerPrefix + "bounds1=" + mBounds1.toShortString());
pw.println(innerPrefix + "dividerBounds=" + mDividerBounds.toShortString());
pw.println(innerPrefix + "bounds2=" + mBounds2.toShortString());
@@ -1151,14 +1161,16 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mTargetYOffset = needOffset ? getTargetYOffset() : 0;
if (mTargetYOffset != mLastYOffset) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "Split IME animation starting, fromY=%d toY=%d",
+ mLastYOffset, mTargetYOffset);
// Freeze the configuration size with offset to prevent app get a configuration
// changed or relaunch. This is required to make sure client apps will calculate
// insets properly after layout shifted.
if (mTargetYOffset == 0) {
mSplitLayoutHandler.setLayoutOffsetTarget(0, 0, SplitLayout.this);
} else {
- mSplitLayoutHandler.setLayoutOffsetTarget(0, mTargetYOffset - mLastYOffset,
- SplitLayout.this);
+ mSplitLayoutHandler.setLayoutOffsetTarget(0, mTargetYOffset, SplitLayout.this);
}
}
@@ -1183,6 +1195,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public void onImeEndPositioning(int displayId, boolean cancel,
SurfaceControl.Transaction t) {
if (displayId != mDisplayId || !mHasImeFocus || cancel) return;
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "Split IME animation ending, canceled=%b", cancel);
onProgress(1.0f);
mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 00361d9dd9cf..8fb9bda539a0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -62,6 +62,10 @@ public final class SplitWindowManager extends WindowlessWindowManager {
// Used to "pass" a transaction to WWM.remove so that view removal can be synchronized.
private SurfaceControl.Transaction mSyncTransaction = null;
+ // For saving/restoring state
+ private boolean mLastDividerInteractive = true;
+ private boolean mLastDividerHandleHidden;
+
public interface ParentContainerCallbacks {
void attachToParentSurface(SurfaceControl.Builder b);
void onLeashReady(SurfaceControl leash);
@@ -107,7 +111,7 @@ public final class SplitWindowManager extends WindowlessWindowManager {
}
/** Inflates {@link DividerView} on to the root surface. */
- void init(SplitLayout splitLayout, InsetsState insetsState) {
+ void init(SplitLayout splitLayout, InsetsState insetsState, boolean isRestoring) {
if (mDividerView != null || mViewHost != null) {
throw new UnsupportedOperationException(
"Try to inflate divider view again without release first");
@@ -130,6 +134,10 @@ public final class SplitWindowManager extends WindowlessWindowManager {
lp.accessibilityTitle = mContext.getResources().getString(R.string.accessibility_divider);
mViewHost.setView(mDividerView, lp);
mDividerView.setup(splitLayout, this, mViewHost, insetsState);
+ if (isRestoring) {
+ mDividerView.setInteractive(mLastDividerInteractive, mLastDividerHandleHidden,
+ "restore_setup");
+ }
}
/**
@@ -138,6 +146,8 @@ public final class SplitWindowManager extends WindowlessWindowManager {
*/
void release(@Nullable SurfaceControl.Transaction t) {
if (mDividerView != null) {
+ mLastDividerInteractive = mDividerView.isInteractive();
+ mLastDividerHandleHidden = mDividerView.isHandleHidden();
mDividerView = null;
}
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 449bef5608c9..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);
@@ -1666,7 +1686,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
void finishEnterSplitScreen(SurfaceControl.Transaction finishT) {
- mSplitLayout.update(finishT);
+ mSplitLayout.update(finishT, true /* resetImePosition */);
mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash,
getMainStageBounds());
mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash,
@@ -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()) {
@@ -1860,9 +1881,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
&& mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)
&& mMainStage.isActive()) {
// Clear the divider remote animating flag as the divider will be re-rendered to apply
- // the new rotation config.
+ // the new rotation config. Don't reset the IME state since those updates are not in
+ // sync with task info changes.
mIsDividerRemoteAnimating = false;
- mSplitLayout.update(null /* t */);
+ mSplitLayout.update(null /* t */, false /* resetImePosition */);
onLayoutSizeChanged(mSplitLayout);
}
}
@@ -1928,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();
@@ -2122,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();
@@ -2325,7 +2349,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
*/
public void updateSurfaces(SurfaceControl.Transaction transaction) {
updateSurfaceBounds(mSplitLayout, transaction, /* applyResizingOffset */ false);
- mSplitLayout.update(transaction);
+ mSplitLayout.update(transaction, true /* resetImePosition */);
}
private void onDisplayChange(int displayId, int fromRotation, int toRotation,
@@ -2598,7 +2622,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final TransitionInfo.Change change = info.getChanges().get(iC);
if (change.getMode() == TRANSIT_CHANGE
&& (change.getFlags() & FLAG_IS_DISPLAY) != 0) {
- mSplitLayout.update(startTransaction);
+ // Don't reset the IME state since those updates are not in sync with the
+ // display change transition
+ mSplitLayout.update(startTransaction, false /* resetImePosition */);
}
if (mMixedHandler.isEnteringPip(change, transitType)) {
@@ -2699,7 +2725,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
startTransaction, finishTransaction, finishCallback)) {
if (mSplitTransitions.isPendingResize(transition)) {
// Only need to update in resize because divider exist before transition.
- mSplitLayout.update(startTransaction);
+ mSplitLayout.update(startTransaction, true /* resetImePosition */);
startTransaction.apply();
}
return true;
@@ -3242,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/common/split/DividerViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
index 145c8f0ab8af..636c6326d213 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
@@ -69,7 +69,7 @@ public class DividerViewTest extends ShellTestCase {
SplitWindowManager splitWindowManager = new SplitWindowManager("TestSplitWindowManager",
mContext,
configuration, mCallbacks);
- splitWindowManager.init(mSplitLayout, new InsetsState());
+ splitWindowManager.init(mSplitLayout, new InsetsState(), false /* isRestoring */);
mDividerView = spy((DividerView) splitWindowManager.getDividerView());
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
index 2e5078d86a8b..150aa13f2d00 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -59,7 +59,7 @@ public class SplitWindowManagerTests extends ShellTestCase {
@Test
@UiThreadTest
public void testInitRelease() {
- mSplitWindowManager.init(mSplitLayout, new InsetsState());
+ mSplitWindowManager.init(mSplitLayout, new InsetsState(), false /* isRestoring */);
assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
mSplitWindowManager.release(null /* t */);
assertThat(mSplitWindowManager.getSurfaceControl()).isNull();
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/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 8445032293dd..69718a6c4b3e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -43,12 +43,15 @@ cc_test {
},
shared_libs: [
"libandroid_runtime",
+ "libbase",
+ "libinput",
"libinputservice",
"libhwui",
"libgui",
"libutils",
],
static_libs: [
+ "libflagtest",
"libgmock",
"libgtest",
],
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index d9efd3c2fd83..adfa91e96ebb 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <com_android_input_flags.h>
+#include <flag_macros.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <input/PointerController.h>
@@ -28,6 +30,8 @@
namespace android {
+namespace input_flags = com::android::input::flags;
+
enum TestCursorType {
CURSOR_TYPE_DEFAULT = 0,
CURSOR_TYPE_HOVER,
@@ -261,7 +265,20 @@ TEST_F(PointerControllerTest, useStylusTypeForStylusHover) {
mPointerController->reloadPointerResources();
}
-TEST_F(PointerControllerTest, updatePointerIcon) {
+TEST_F_WITH_FLAGS(PointerControllerTest, setPresentationBeforeDisplayViewportDoesNotLoadResources,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(input_flags, enable_pointer_choreographer))) {
+ // Setting the presentation mode before a display viewport is set will not load any resources.
+ mPointerController->setPresentation(PointerController::Presentation::POINTER);
+ ASSERT_TRUE(mPolicy->noResourcesAreLoaded());
+
+ // When the display is set, then the resources are loaded.
+ ensureDisplayViewportIsSet();
+ ASSERT_TRUE(mPolicy->allResourcesAreLoaded());
+}
+
+TEST_F_WITH_FLAGS(PointerControllerTest, updatePointerIcon,
+ REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(input_flags,
+ enable_pointer_choreographer))) {
ensureDisplayViewportIsSet();
mPointerController->setPresentation(PointerController::Presentation::POINTER);
mPointerController->unfade(PointerController::Transition::IMMEDIATE);
@@ -277,6 +294,24 @@ TEST_F(PointerControllerTest, updatePointerIcon) {
mPointerController->updatePointerIcon(static_cast<PointerIconStyle>(type));
}
+TEST_F_WITH_FLAGS(PointerControllerTest, updatePointerIconWithChoreographer,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(input_flags, enable_pointer_choreographer))) {
+ // When PointerChoreographer is enabled, the presentation mode is set before the viewport.
+ mPointerController->setPresentation(PointerController::Presentation::POINTER);
+ ensureDisplayViewportIsSet();
+ mPointerController->unfade(PointerController::Transition::IMMEDIATE);
+
+ int32_t type = CURSOR_TYPE_ADDITIONAL;
+ std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type);
+ EXPECT_CALL(*mPointerSprite, setVisible(true));
+ EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+ EXPECT_CALL(*mPointerSprite,
+ setIcon(AllOf(Field(&SpriteIcon::style, static_cast<PointerIconStyle>(type)),
+ Field(&SpriteIcon::hotSpotX, hotspot.first),
+ Field(&SpriteIcon::hotSpotY, hotspot.second))));
+ mPointerController->updatePointerIcon(static_cast<PointerIconStyle>(type));
+}
+
TEST_F(PointerControllerTest, setCustomPointerIcon) {
ensureDisplayViewportIsSet();
mPointerController->unfade(PointerController::Transition::IMMEDIATE);
diff --git a/media/OWNERS b/media/OWNERS
index 4a6648e91af4..994a7b810009 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -21,7 +21,6 @@ wonsik@google.com
include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
# SEO
-sungsoo@google.com
# SEA/KIR/BVE
jtinker@google.com
diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS
index bbe5e06bb282..058c5be6af6c 100644
--- a/media/java/android/media/OWNERS
+++ b/media/java/android/media/OWNERS
@@ -2,7 +2,6 @@
fgoldfain@google.com
elaurent@google.com
lajos@google.com
-sungsoo@google.com
jmtrivi@google.com
# go/android-fwk-media-solutions for info on areas of ownership.
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/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index e3b93ba34045..f4641b9930cb 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -202,11 +202,6 @@
<!-- Dialog attributes to indicate parse errors -->
<string name="Parse_error_dlg_text">There was a problem parsing the package.</string>
- <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=30] -->
- <string name="wear_not_allowed_dlg_title">Android Wear</string>
- <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=none] -->
- <string name="wear_not_allowed_dlg_text">Install/Uninstall actions not supported on Wear.</string>
-
<!-- Message that the app to be installed is being staged [CHAR LIMIT=50] -->
<string name="message_staging">Staging app&#8230;</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
index e07e9425808e..2da8c8c69ff8 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
@@ -156,10 +156,9 @@ public class UninstallAlertDialogFragment extends DialogFragment implements
if (customUserManager.isUserOfType(USER_TYPE_PROFILE_MANAGED)
&& customUserManager.isSameProfileGroup(dialogInfo.user, myUserHandle)) {
messageBuilder.append(isArchive
- ? getString(R.string.archive_application_text_current_user_work_profile,
- userName) : getString(
- R.string.uninstall_application_text_current_user_work_profile,
- userName));
+ ? getString(R.string.archive_application_text_current_user_work_profile)
+ : getString(
+ R.string.uninstall_application_text_current_user_work_profile));
} else if (customUserManager.isUserOfType(USER_TYPE_PROFILE_CLONE)
&& customUserManager.isSameProfileGroup(dialogInfo.user, myUserHandle)) {
mIsClonedApp = true;
@@ -168,11 +167,11 @@ public class UninstallAlertDialogFragment extends DialogFragment implements
} else if (Flags.allowPrivateProfile()
&& customUserManager.isPrivateProfile()
&& customUserManager.isSameProfileGroup(dialogInfo.user, myUserHandle)) {
- messageBuilder.append(isArchive ? getString(
- R.string.archive_application_text_current_user_private_profile,
- userName) : getString(
- R.string.uninstall_application_text_current_user_private_profile,
- userName));
+ messageBuilder.append(
+ isArchive ? getString(
+ R.string.archive_application_text_current_user_private_profile)
+ : getString(
+ R.string.uninstall_application_text_current_user_private_profile));
} else if (isArchive) {
messageBuilder.append(
getString(R.string.archive_application_text_user, userName));
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/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
index d0d2dc0083a6..e099f1124bf1 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
@@ -20,13 +20,17 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOn
+private const val TAG = "BroadcastReceiverFlow"
+
/**
* A [BroadcastReceiver] flow for the given [intentFilter].
*/
@@ -39,4 +43,6 @@ fun Context.broadcastReceiverFlow(intentFilter: IntentFilter): Flow<Intent> = ca
registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
awaitClose { unregisterReceiver(broadcastReceiver) }
+}.catch { e ->
+ Log.e(TAG, "Error while broadcastReceiverFlow", e)
}.conflate().flowOn(Dispatchers.Default)
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
index dfaf3c66ff8d..eef5225aef42 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
@@ -31,8 +31,10 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doThrow
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class BroadcastReceiverFlowTest {
@@ -74,6 +76,18 @@ class BroadcastReceiverFlowTest {
assertThat(onReceiveIsCalled).isTrue()
}
+ @Test
+ fun broadcastReceiverFlow_unregisterReceiverThrowException_noCrash() = runBlocking {
+ context.stub {
+ on { unregisterReceiver(any()) } doThrow IllegalArgumentException()
+ }
+ val flow = context.broadcastReceiverFlow(INTENT_FILTER)
+
+ flow.firstWithTimeoutOrNull()
+
+ assertThat(registeredBroadcastReceiver).isNotNull()
+ }
+
private companion object {
val INTENT_FILTER = IntentFilter()
}
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 69b61c74625e..49ac0f864ed7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -28,10 +28,11 @@ 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.bluetooth.BluetoothStatusCodes;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -42,26 +43,30 @@ import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
+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;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
/**
- * LocalBluetoothLeBroadcast provides an interface between the Settings app
- * and the functionality of the local {@link BluetoothLeBroadcast}.
- * Use the {@link BluetoothLeBroadcast.Callback} to get the result callback.
+ * LocalBluetoothLeBroadcast provides an interface between the Settings app and the functionality of
+ * the local {@link BluetoothLeBroadcast}. Use the {@link BluetoothLeBroadcast.Callback} to get the
+ * result callback.
*/
public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
private static final String TAG = "LocalBluetoothLeBroadcast";
@@ -74,11 +79,12 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
// Order of this profile in device profiles list
private static final int ORDINAL = 1;
private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
- private static final Uri[] SETTINGS_URIS = new Uri[]{
- Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO),
- Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE),
- Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME),
- };
+ private static final Uri[] SETTINGS_URIS =
+ new Uri[] {
+ Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO),
+ Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE),
+ Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME),
+ };
private BluetoothLeBroadcast mServiceBroadcast;
private BluetoothLeBroadcastAssistant mServiceBroadcastAssistant;
@@ -95,62 +101,82 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
private Executor mExecutor;
private ContentResolver mContentResolver;
private ContentObserver mSettingsObserver;
+ // Cached broadcast callbacks being register before service is connected.
+ private Map<BluetoothLeBroadcast.Callback, Executor> mCachedBroadcastCallbackExecutorMap =
+ new ConcurrentHashMap<>();
- private final ServiceListener mServiceListener = new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (DEBUG) {
- Log.d(TAG, "Bluetooth service connected: " + profile);
- }
- if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST) && !mIsBroadcastProfileReady) {
- mServiceBroadcast = (BluetoothLeBroadcast) proxy;
- mIsBroadcastProfileReady = true;
- registerServiceCallBack(mExecutor, mBroadcastCallback);
- List<BluetoothLeBroadcastMetadata> metadata = getAllBroadcastMetadata();
- if (!metadata.isEmpty()) {
- updateBroadcastInfoFromBroadcastMetadata(metadata.get(0));
+ private final ServiceListener mServiceListener =
+ new ServiceListener() {
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (DEBUG) {
+ Log.d(TAG, "Bluetooth service connected: " + profile);
+ }
+ if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST)
+ && !mIsBroadcastProfileReady) {
+ mServiceBroadcast = (BluetoothLeBroadcast) proxy;
+ mIsBroadcastProfileReady = true;
+ registerServiceCallBack(mExecutor, mBroadcastCallback);
+ List<BluetoothLeBroadcastMetadata> metadata = getAllBroadcastMetadata();
+ if (!metadata.isEmpty()) {
+ updateBroadcastInfoFromBroadcastMetadata(metadata.get(0));
+ }
+ registerContentObserver();
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onServiceConnected: register "
+ + "mCachedBroadcastCallbackExecutorMap = "
+ + mCachedBroadcastCallbackExecutorMap);
+ }
+ mCachedBroadcastCallbackExecutorMap.forEach(
+ (callback, executor) ->
+ registerServiceCallBack(executor, callback));
+ } else if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
+ && !mIsBroadcastAssistantProfileReady) {
+ mIsBroadcastAssistantProfileReady = true;
+ mServiceBroadcastAssistant = (BluetoothLeBroadcastAssistant) proxy;
+ registerBroadcastAssistantCallback(mExecutor, mBroadcastAssistantCallback);
+ }
}
- registerContentObserver();
- } else if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
- && !mIsBroadcastAssistantProfileReady) {
- mIsBroadcastAssistantProfileReady = true;
- mServiceBroadcastAssistant = (BluetoothLeBroadcastAssistant) proxy;
- registerBroadcastAssistantCallback(mExecutor, mBroadcastAssistantCallback);
- }
- }
- @Override
- public void onServiceDisconnected(int profile) {
- if (DEBUG) {
- Log.d(TAG, "Bluetooth service disconnected");
- }
- if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST) && mIsBroadcastProfileReady) {
- mIsBroadcastProfileReady = false;
- unregisterServiceCallBack(mBroadcastCallback);
- }
- if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
- && mIsBroadcastAssistantProfileReady) {
- mIsBroadcastAssistantProfileReady = false;
- unregisterBroadcastAssistantCallback(mBroadcastAssistantCallback);
- }
+ @Override
+ public void onServiceDisconnected(int profile) {
+ if (DEBUG) {
+ Log.d(TAG, "Bluetooth service disconnected: " + profile);
+ }
+ if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST)
+ && mIsBroadcastProfileReady) {
+ mIsBroadcastProfileReady = false;
+ unregisterServiceCallBack(mBroadcastCallback);
+ mCachedBroadcastCallbackExecutorMap.clear();
+ }
+ if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
+ && mIsBroadcastAssistantProfileReady) {
+ mIsBroadcastAssistantProfileReady = false;
+ unregisterBroadcastAssistantCallback(mBroadcastAssistantCallback);
+ }
- if (!mIsBroadcastAssistantProfileReady && !mIsBroadcastProfileReady) {
- unregisterContentObserver();
- }
- }
- };
+ if (!mIsBroadcastAssistantProfileReady && !mIsBroadcastProfileReady) {
+ unregisterContentObserver();
+ }
+ }
+ };
private final BluetoothLeBroadcast.Callback mBroadcastCallback =
new BluetoothLeBroadcast.Callback() {
@Override
public void onBroadcastStarted(int reason, int broadcastId) {
if (DEBUG) {
- Log.d(TAG,
- "onBroadcastStarted(), reason = " + reason + ", broadcastId = "
+ Log.d(
+ TAG,
+ "onBroadcastStarted(), reason = "
+ + reason
+ + ", broadcastId = "
+ broadcastId);
}
setLatestBroadcastId(broadcastId);
- setAppSourceName(mNewAppSourceName, /*updateContentResolver=*/ true);
+ setAppSourceName(mNewAppSourceName, /* updateContentResolver= */ true);
}
@Override
@@ -161,8 +187,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
@Override
- public void onBroadcastMetadataChanged(int broadcastId,
- @NonNull BluetoothLeBroadcastMetadata metadata) {
+ public void onBroadcastMetadataChanged(
+ int broadcastId, @NonNull BluetoothLeBroadcastMetadata metadata) {
if (DEBUG) {
Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId);
}
@@ -172,8 +198,11 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
@Override
public void onBroadcastStopped(int reason, int broadcastId) {
if (DEBUG) {
- Log.d(TAG,
- "onBroadcastStopped(), reason = " + reason + ", broadcastId = "
+ Log.d(
+ TAG,
+ "onBroadcastStopped(), reason = "
+ + reason
+ + ", broadcastId = "
+ broadcastId);
}
@@ -191,37 +220,42 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
@Override
public void onBroadcastUpdated(int reason, int broadcastId) {
if (DEBUG) {
- Log.d(TAG,
- "onBroadcastUpdated(), reason = " + reason + ", broadcastId = "
+ Log.d(
+ TAG,
+ "onBroadcastUpdated(), reason = "
+ + reason
+ + ", broadcastId = "
+ broadcastId);
}
setLatestBroadcastId(broadcastId);
- setAppSourceName(mNewAppSourceName, /*updateContentResolver=*/ true);
+ setAppSourceName(mNewAppSourceName, /* updateContentResolver= */ true);
}
@Override
public void onBroadcastUpdateFailed(int reason, int broadcastId) {
if (DEBUG) {
- Log.d(TAG,
- "onBroadcastUpdateFailed(), reason = " + reason + ", broadcastId = "
+ Log.d(
+ TAG,
+ "onBroadcastUpdateFailed(), reason = "
+ + reason
+ + ", broadcastId = "
+ broadcastId);
}
}
@Override
- public void onPlaybackStarted(int reason, int broadcastId) {
- }
+ public void onPlaybackStarted(int reason, int broadcastId) {}
@Override
- public void onPlaybackStopped(int reason, int broadcastId) {
- }
+ public void onPlaybackStopped(int reason, int broadcastId) {}
};
private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
new BluetoothLeBroadcastAssistant.Callback() {
@Override
- public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId,
- int reason) {}
+ public void onSourceAdded(
+ @NonNull BluetoothDevice sink, int sourceId, int reason) {}
+
@Override
public void onSearchStarted(int reason) {}
@@ -238,38 +272,65 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {}
@Override
- public void onSourceAddFailed(@NonNull BluetoothDevice sink,
- @NonNull BluetoothLeBroadcastMetadata source, int reason) {}
+ public void onSourceAddFailed(
+ @NonNull BluetoothDevice sink,
+ @NonNull BluetoothLeBroadcastMetadata source,
+ int reason) {}
@Override
- public void onSourceModified(@NonNull BluetoothDevice sink, int sourceId,
- int reason) {}
+ public void onSourceModified(
+ @NonNull BluetoothDevice sink, int sourceId, int reason) {}
@Override
- public void onSourceModifyFailed(@NonNull BluetoothDevice sink, int sourceId,
- int reason) {}
+ public void onSourceModifyFailed(
+ @NonNull BluetoothDevice sink, int sourceId, int reason) {}
@Override
- public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId,
- int reason) {
+ public void onSourceRemoved(
+ @NonNull BluetoothDevice sink, int sourceId, int reason) {
if (DEBUG) {
- Log.d(TAG, "onSourceRemoved(), sink = " + sink + ", reason = "
- + reason + ", sourceId = " + sourceId);
+ Log.d(
+ TAG,
+ "onSourceRemoved(), sink = "
+ + sink
+ + ", reason = "
+ + reason
+ + ", sourceId = "
+ + sourceId);
}
}
@Override
- public void onSourceRemoveFailed(@NonNull BluetoothDevice sink, int sourceId,
- int reason) {
+ public void onSourceRemoveFailed(
+ @NonNull BluetoothDevice sink, int sourceId, int reason) {
if (DEBUG) {
- Log.d(TAG, "onSourceRemoveFailed(), sink = " + sink + ", reason = "
- + reason + ", sourceId = " + sourceId);
+ Log.d(
+ TAG,
+ "onSourceRemoveFailed(), sink = "
+ + sink
+ + ", reason = "
+ + reason
+ + ", sourceId = "
+ + sourceId);
}
}
@Override
- public void onReceiveStateChanged(@NonNull BluetoothDevice sink, int sourceId,
- @NonNull BluetoothLeBroadcastReceiveState state) {}
+ public void onReceiveStateChanged(
+ @NonNull BluetoothDevice sink,
+ int sourceId,
+ @NonNull BluetoothLeBroadcastReceiveState state) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onReceiveStateChanged(), sink = "
+ + sink
+ + ", sourceId = "
+ + sourceId
+ + ", state = "
+ + state);
+ }
+ }
};
private class BroadcastSettingsObserver extends ContentObserver {
@@ -296,8 +357,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
BluetoothAdapter.getDefaultAdapter()
.getProfileProxy(context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST);
BluetoothAdapter.getDefaultAdapter()
- .getProfileProxy(context, mServiceListener,
- BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+ .getProfileProxy(
+ context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
}
/**
@@ -312,20 +373,91 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
String programInfo = getProgramInfo();
if (DEBUG) {
- Log.d(TAG,
- "startBroadcast: language = " + language + " ,programInfo = " + programInfo);
+ Log.d(TAG, "startBroadcast: language = " + language + " ,programInfo = " + programInfo);
}
buildContentMetadata(language, programInfo);
- mServiceBroadcast.startBroadcast(mBluetoothLeAudioContentMetadata,
+ mServiceBroadcast.startBroadcast(
+ mBluetoothLeAudioContentMetadata,
(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;
}
public void setProgramInfo(String programInfo) {
- setProgramInfo(programInfo, /*updateContentResolver=*/ true);
+ setProgramInfo(programInfo, /* updateContentResolver= */ true);
}
private void setProgramInfo(String programInfo, boolean updateContentResolver) {
@@ -344,8 +476,10 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
Log.d(TAG, "mContentResolver is null");
return;
}
- Settings.Secure.putString(mContentResolver,
- Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO, programInfo);
+ Settings.Secure.putString(
+ mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO,
+ programInfo);
}
}
@@ -354,7 +488,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
public void setBroadcastCode(byte[] broadcastCode) {
- setBroadcastCode(broadcastCode, /*updateContentResolver=*/ true);
+ setBroadcastCode(broadcastCode, /* updateContentResolver= */ true);
}
private void setBroadcastCode(byte[] broadcastCode, boolean updateContentResolver) {
@@ -372,7 +506,9 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
Log.d(TAG, "mContentResolver is null");
return;
}
- Settings.Secure.putString(mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE,
+ Settings.Secure.putString(
+ mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE,
new String(broadcastCode, StandardCharsets.UTF_8));
}
}
@@ -401,8 +537,10 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
Log.d(TAG, "mContentResolver is null");
return;
}
- Settings.Secure.putString(mContentResolver,
- Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME, mAppSourceName);
+ Settings.Secure.putString(
+ mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME,
+ mAppSourceName);
}
}
@@ -427,10 +565,11 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
if (mBluetoothLeBroadcastMetadata == null) {
final List<BluetoothLeBroadcastMetadata> metadataList =
mServiceBroadcast.getAllBroadcastMetadata();
- mBluetoothLeBroadcastMetadata = metadataList.stream()
- .filter(i -> i.getBroadcastId() == mBroadcastId)
- .findFirst()
- .orElse(null);
+ mBluetoothLeBroadcastMetadata =
+ metadataList.stream()
+ .filter(i -> i.getBroadcastId() == mBroadcastId)
+ .findFirst()
+ .orElse(null);
}
return mBluetoothLeBroadcastMetadata;
}
@@ -440,22 +579,27 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
Log.d(TAG, "updateBroadcastInfoFromContentProvider: mContentResolver is null");
return;
}
- String programInfo = Settings.Secure.getString(mContentResolver,
- Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO);
+ String programInfo =
+ Settings.Secure.getString(
+ mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO);
if (programInfo == null) {
programInfo = getDefaultValueOfProgramInfo();
}
- setProgramInfo(programInfo, /*updateContentResolver=*/ false);
+ setProgramInfo(programInfo, /* updateContentResolver= */ false);
- String prefBroadcastCode = Settings.Secure.getString(mContentResolver,
- Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE);
- byte[] broadcastCode = (prefBroadcastCode == null) ? getDefaultValueOfBroadcastCode()
- : prefBroadcastCode.getBytes(StandardCharsets.UTF_8);
- setBroadcastCode(broadcastCode, /*updateContentResolver=*/ false);
+ String prefBroadcastCode =
+ Settings.Secure.getString(
+ mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE);
+ byte[] broadcastCode =
+ (prefBroadcastCode == null)
+ ? getDefaultValueOfBroadcastCode()
+ : prefBroadcastCode.getBytes(StandardCharsets.UTF_8);
+ setBroadcastCode(broadcastCode, /* updateContentResolver= */ false);
- String appSourceName = Settings.Secure.getString(mContentResolver,
- Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME);
- setAppSourceName(appSourceName, /*updateContentResolver=*/ false);
+ String appSourceName =
+ Settings.Secure.getString(
+ mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME);
+ setAppSourceName(appSourceName, /* updateContentResolver= */ false);
}
private void updateBroadcastInfoFromBroadcastMetadata(
@@ -474,12 +618,12 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
BluetoothLeAudioContentMetadata contentMetadata = subgroup.get(0).getContentMetadata();
setProgramInfo(contentMetadata.getProgramInfo());
- setAppSourceName(getAppSourceName(), /*updateContentResolver=*/ true);
+ setAppSourceName(getAppSourceName(), /* updateContentResolver= */ true);
}
/**
- * Stop the latest LE Broadcast. If the system stopped the LE Broadcast, then the system
- * calls the corresponding callback {@link BluetoothLeBroadcast.Callback}.
+ * Stop the latest LE Broadcast. If the system stopped the LE Broadcast, then the system calls
+ * the corresponding callback {@link BluetoothLeBroadcast.Callback}.
*/
public void stopLatestBroadcast() {
stopBroadcast(mBroadcastId);
@@ -511,7 +655,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
String programInfo = getProgramInfo();
if (DEBUG) {
- Log.d(TAG,
+ Log.d(
+ TAG,
"updateBroadcast: language = " + language + " ,programInfo = " + programInfo);
}
mNewAppSourceName = appSourceName;
@@ -519,50 +664,79 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
mServiceBroadcast.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata);
}
- public void registerServiceCallBack(@NonNull @CallbackExecutor Executor executor,
+ /**
+ * Register Broadcast Callbacks to track its state and receivers
+ *
+ * @param executor Executor object for callback
+ * @param callback Callback object to be registered
+ */
+ public void registerServiceCallBack(
+ @NonNull @CallbackExecutor Executor executor,
@NonNull BluetoothLeBroadcast.Callback callback) {
if (mServiceBroadcast == null) {
- Log.d(TAG, "The BluetoothLeBroadcast is null.");
+ Log.d(TAG, "registerServiceCallBack failed, the BluetoothLeBroadcast is null.");
+ mCachedBroadcastCallbackExecutorMap.putIfAbsent(callback, executor);
return;
}
- mServiceBroadcast.registerCallback(executor, callback);
+ try {
+ mServiceBroadcast.registerCallback(executor, callback);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "registerServiceCallBack failed. " + e.getMessage());
+ }
}
/**
- * Register Broadcast Assistant Callbacks to track it's state and receivers
+ * Register Broadcast Assistant Callbacks to track its state and receivers
*
* @param executor Executor object for callback
* @param callback Callback object to be registered
*/
- public void registerBroadcastAssistantCallback(@NonNull @CallbackExecutor Executor executor,
+ private void registerBroadcastAssistantCallback(
+ @NonNull @CallbackExecutor Executor executor,
@NonNull BluetoothLeBroadcastAssistant.Callback callback) {
if (mServiceBroadcastAssistant == null) {
- Log.d(TAG, "The BluetoothLeBroadcastAssisntant is null.");
+ Log.d(
+ TAG,
+ "registerBroadcastAssistantCallback failed, "
+ + "the BluetoothLeBroadcastAssistant is null.");
return;
}
mServiceBroadcastAssistant.registerCallback(executor, callback);
}
+ /**
+ * Unregister previously registered Broadcast Callbacks
+ *
+ * @param callback Callback object to be unregistered
+ */
public void unregisterServiceCallBack(@NonNull BluetoothLeBroadcast.Callback callback) {
+ mCachedBroadcastCallbackExecutorMap.remove(callback);
if (mServiceBroadcast == null) {
- Log.d(TAG, "The BluetoothLeBroadcast is null.");
+ Log.d(TAG, "unregisterServiceCallBack failed, the BluetoothLeBroadcast is null.");
return;
}
- mServiceBroadcast.unregisterCallback(callback);
+ try {
+ mServiceBroadcast.unregisterCallback(callback);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "unregisterServiceCallBack failed. " + e.getMessage());
+ }
}
/**
- * Unregister previousely registered Broadcast Assistant Callbacks
+ * Unregister previously registered Broadcast Assistant Callbacks
*
* @param callback Callback object to be unregistered
*/
- public void unregisterBroadcastAssistantCallback(
+ private void unregisterBroadcastAssistantCallback(
@NonNull BluetoothLeBroadcastAssistant.Callback callback) {
if (mServiceBroadcastAssistant == null) {
- Log.d(TAG, "The BluetoothLeBroadcastAssisntant is null.");
+ Log.d(
+ TAG,
+ "unregisterBroadcastAssistantCallback, "
+ + "the BluetoothLeBroadcastAssistant is null.");
return;
}
@@ -570,8 +744,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
private void buildContentMetadata(String language, String programInfo) {
- mBluetoothLeAudioContentMetadata = mBuilder.setLanguage(language).setProgramInfo(
- programInfo).build();
+ mBluetoothLeAudioContentMetadata =
+ mBuilder.setLanguage(language).setProgramInfo(programInfo).build();
}
public LocalBluetoothLeBroadcastMetadata getLocalBluetoothLeBroadcastMetaData() {
@@ -600,9 +774,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
return true;
}
- /**
- * Not supported since LE Audio Broadcasts do not establish a connection.
- */
+ /** Not supported since LE Audio Broadcasts do not establish a connection. */
public int getConnectionStatus(BluetoothDevice device) {
if (mServiceBroadcast == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -611,9 +783,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
return mServiceBroadcast.getConnectionState(device);
}
- /**
- * Not supported since LE Audio Broadcasts do not establish a connection.
- */
+ /** Not supported since LE Audio Broadcasts do not establish a connection. */
public List<BluetoothDevice> getConnectedDevices() {
if (mServiceBroadcast == null) {
return new ArrayList<BluetoothDevice>(0);
@@ -622,8 +792,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
return mServiceBroadcast.getConnectedDevices();
}
- public @NonNull
- List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata() {
+ /** Get all broadcast metadata. */
+ public @NonNull List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata() {
if (mServiceBroadcast == null) {
Log.d(TAG, "The BluetoothLeBroadcast is null.");
return Collections.emptyList();
@@ -640,16 +810,14 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
return !mServiceBroadcast.getAllBroadcastMetadata().isEmpty();
}
- /**
- * Service does not provide method to get/set policy.
- */
+ /** Service does not provide method to get/set policy. */
public int getConnectionPolicy(BluetoothDevice device) {
return CONNECTION_POLICY_FORBIDDEN;
}
/**
- * Service does not provide "setEnabled" method. Please use {@link #startBroadcast},
- * {@link #stopBroadcast()} or {@link #updateBroadcast(String, String)}
+ * Service does not provide "setEnabled" method. Please use {@link #startBroadcast}, {@link
+ * #stopBroadcast()} or {@link #updateBroadcast(String, String)}
*/
public boolean setEnabled(BluetoothDevice device, boolean enabled) {
return false;
@@ -683,9 +851,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
if (mServiceBroadcast != null) {
try {
- BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
- BluetoothProfile.LE_AUDIO_BROADCAST,
- mServiceBroadcast);
+ BluetoothAdapter.getDefaultAdapter()
+ .closeProfileProxy(BluetoothProfile.LE_AUDIO_BROADCAST, mServiceBroadcast);
mServiceBroadcast = null;
} catch (Throwable t) {
Log.w(TAG, "Error cleaning up LeAudio proxy", t);
@@ -694,13 +861,13 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
private String getDefaultValueOfProgramInfo() {
- //set the default value;
+ // set the default value;
int postfix = ThreadLocalRandom.current().nextInt(DEFAULT_CODE_MIN, DEFAULT_CODE_MAX);
return BluetoothAdapter.getDefaultAdapter().getName() + UNDERLINE + postfix;
}
private byte[] getDefaultValueOfBroadcastCode() {
- //set the default value;
+ // set the default value;
return generateRandomPassword().getBytes(StandardCharsets.UTF_8);
}
@@ -708,14 +875,14 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
if (DEBUG) {
Log.d(TAG, "resetCacheInfo:");
}
- setAppSourceName("", /*updateContentResolver=*/ true);
+ setAppSourceName("", /* updateContentResolver= */ true);
mBluetoothLeBroadcastMetadata = null;
mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER;
}
private String generateRandomPassword() {
String randomUUID = UUID.randomUUID().toString();
- //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
+ // first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
return randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
}
@@ -752,5 +919,4 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
}
}
-
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
index bb103b8896fd..34008ac56042 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
@@ -39,13 +39,14 @@ import com.android.settingslib.R;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
-
/**
- * LocalBluetoothLeBroadcastAssistant provides an interface between the Settings app
- * and the functionality of the local {@link BluetoothLeBroadcastAssistant}.
- * Use the {@link BluetoothLeBroadcastAssistant.Callback} to get the result callback.
+ * LocalBluetoothLeBroadcastAssistant provides an interface between the Settings app and the
+ * functionality of the local {@link BluetoothLeBroadcastAssistant}. Use the {@link
+ * BluetoothLeBroadcastAssistant.Callback} to get the result callback.
*/
public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile {
private static final String TAG = "LocalBluetoothLeBroadcastAssistant";
@@ -62,58 +63,76 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
private BluetoothLeBroadcastMetadata.Builder mBuilder;
private boolean mIsProfileReady;
+ // Cached assistant callbacks being register before service is connected.
+ private final Map<BluetoothLeBroadcastAssistant.Callback, Executor> mCachedCallbackExecutorMap =
+ new ConcurrentHashMap<>();
+
+ private final ServiceListener mServiceListener =
+ new ServiceListener() {
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (DEBUG) {
+ Log.d(TAG, "Bluetooth service connected");
+ }
+ mService = (BluetoothLeBroadcastAssistant) proxy;
+ // We just bound to the service, so refresh the UI for any connected LeAudio
+ // devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ while (!deviceList.isEmpty()) {
+ BluetoothDevice nextDevice = deviceList.remove(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "LocalBluetoothLeBroadcastAssistant found new device: "
+ + nextDevice);
+ }
+ device = mDeviceManager.addDevice(nextDevice);
+ }
+ device.onProfileStateChanged(
+ LocalBluetoothLeBroadcastAssistant.this,
+ BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
- private final ServiceListener mServiceListener = new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (DEBUG) {
- Log.d(TAG, "Bluetooth service connected");
- }
- mService = (BluetoothLeBroadcastAssistant) proxy;
- // We just bound to the service, so refresh the UI for any connected LeAudio devices.
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
- while (!deviceList.isEmpty()) {
- BluetoothDevice nextDevice = deviceList.remove(0);
- CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
- // we may add a new device here, but generally this should not happen
- if (device == null) {
+ mProfileManager.callServiceConnectedListeners();
+ mIsProfileReady = true;
if (DEBUG) {
- Log.d(TAG, "LocalBluetoothLeBroadcastAssistant found new device: "
- + nextDevice);
+ Log.d(
+ TAG,
+ "onServiceConnected, register mCachedCallbackExecutorMap = "
+ + mCachedCallbackExecutorMap);
}
- device = mDeviceManager.addDevice(nextDevice);
+ mCachedCallbackExecutorMap.forEach(
+ (callback, executor) -> registerServiceCallBack(executor, callback));
}
- device.onProfileStateChanged(LocalBluetoothLeBroadcastAssistant.this,
- BluetoothProfile.STATE_CONNECTED);
- device.refresh();
- }
- mProfileManager.callServiceConnectedListeners();
- mIsProfileReady = true;
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- if (profile != BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT) {
- Log.d(TAG, "The profile is not LE_AUDIO_BROADCAST_ASSISTANT");
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "Bluetooth service disconnected");
- }
- mProfileManager.callServiceDisconnectedListeners();
- mIsProfileReady = false;
- }
- };
+ @Override
+ public void onServiceDisconnected(int profile) {
+ if (profile != BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT) {
+ Log.d(TAG, "The profile is not LE_AUDIO_BROADCAST_ASSISTANT");
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Bluetooth service disconnected");
+ }
+ mProfileManager.callServiceDisconnectedListeners();
+ mIsProfileReady = false;
+ mCachedCallbackExecutorMap.clear();
+ }
+ };
- public LocalBluetoothLeBroadcastAssistant(Context context,
+ public LocalBluetoothLeBroadcastAssistant(
+ Context context,
CachedBluetoothDeviceManager deviceManager,
LocalBluetoothProfileManager profileManager) {
mProfileManager = profileManager;
mDeviceManager = deviceManager;
- BluetoothAdapter.getDefaultAdapter().
- getProfileProxy(context, mServiceListener,
- BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+ BluetoothAdapter.getDefaultAdapter()
+ .getProfileProxy(
+ context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
mBuilder = new BluetoothLeBroadcastMetadata.Builder();
}
@@ -123,11 +142,11 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
* @param sink Broadcast Sink to which the Broadcast Source should be added
* @param metadata Broadcast Source metadata to be added to the Broadcast Sink
* @param isGroupOp {@code true} if Application wants to perform this operation for all
- * coordinated set members throughout this session. Otherwise, caller
- * would have to add, modify, and remove individual set members.
+ * coordinated set members throughout this session. Otherwise, caller would have to add,
+ * modify, and remove individual set members.
*/
- public void addSource(BluetoothDevice sink, BluetoothLeBroadcastMetadata metadata,
- boolean isGroupOp) {
+ public void addSource(
+ BluetoothDevice sink, BluetoothLeBroadcastMetadata metadata, boolean isGroupOp) {
if (mService == null) {
Log.d(TAG, "The BluetoothLeBroadcastAssistant is null");
return;
@@ -140,36 +159,55 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
* the qr code string.
*
* @param sink Broadcast Sink to which the Broadcast Source should be added
- * @param sourceAddressType hardware MAC Address of the device. See
- * {@link BluetoothDevice.AddressType}.
+ * @param sourceAddressType hardware MAC Address of the device. See {@link
+ * BluetoothDevice.AddressType}.
* @param presentationDelayMicros presentation delay of this Broadcast Source in microseconds.
* @param sourceAdvertisingSid 1-byte long Advertising_SID of the Broadcast Source.
* @param broadcastId 3-byte long Broadcast_ID of the Broadcast Source.
- * @param paSyncInterval Periodic Advertising Sync interval of the broadcast Source,
- * {@link BluetoothLeBroadcastMetadata#PA_SYNC_INTERVAL_UNKNOWN} if
- * unknown.
+ * @param paSyncInterval Periodic Advertising Sync interval of the broadcast Source, {@link
+ * BluetoothLeBroadcastMetadata#PA_SYNC_INTERVAL_UNKNOWN} if unknown.
* @param isEncrypted whether the Broadcast Source is encrypted.
* @param broadcastCode Broadcast Code for this Broadcast Source, null if code is not required.
* @param sourceDevice source advertiser address.
* @param isGroupOp {@code true} if Application wants to perform this operation for all
- * coordinated set members throughout this session. Otherwise, caller
- * would have to add, modify, and remove individual set members.
+ * coordinated set members throughout this session. Otherwise, caller would have to add,
+ * modify, and remove individual set members.
*/
- public void addSource(@NonNull BluetoothDevice sink, int sourceAddressType,
- int presentationDelayMicros, int sourceAdvertisingSid, int broadcastId,
- int paSyncInterval, boolean isEncrypted, byte[] broadcastCode,
- BluetoothDevice sourceDevice, boolean isGroupOp) {
+ public void addSource(
+ @NonNull BluetoothDevice sink,
+ int sourceAddressType,
+ int presentationDelayMicros,
+ int sourceAdvertisingSid,
+ int broadcastId,
+ int paSyncInterval,
+ boolean isEncrypted,
+ byte[] broadcastCode,
+ BluetoothDevice sourceDevice,
+ boolean isGroupOp) {
if (DEBUG) {
Log.d(TAG, "addSource()");
}
- buildMetadata(sourceAddressType, presentationDelayMicros, sourceAdvertisingSid, broadcastId,
- paSyncInterval, isEncrypted, broadcastCode, sourceDevice);
+ buildMetadata(
+ sourceAddressType,
+ presentationDelayMicros,
+ sourceAdvertisingSid,
+ broadcastId,
+ paSyncInterval,
+ isEncrypted,
+ broadcastCode,
+ sourceDevice);
addSource(sink, mBluetoothLeBroadcastMetadata, isGroupOp);
}
- private void buildMetadata(int sourceAddressType, int presentationDelayMicros,
- int sourceAdvertisingSid, int broadcastId, int paSyncInterval, boolean isEncrypted,
- byte[] broadcastCode, BluetoothDevice sourceDevice) {
+ private void buildMetadata(
+ int sourceAddressType,
+ int presentationDelayMicros,
+ int sourceAdvertisingSid,
+ int broadcastId,
+ int paSyncInterval,
+ boolean isEncrypted,
+ byte[] broadcastCode,
+ BluetoothDevice sourceDevice) {
mBluetoothLeBroadcastMetadata =
mBuilder.setSourceDevice(sourceDevice, sourceAddressType)
.setSourceAdvertisingSid(sourceAdvertisingSid)
@@ -223,10 +261,10 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
/**
* Stops an ongoing search for nearby Broadcast Sources.
*
- * On success, {@link BluetoothLeBroadcastAssistant.Callback#onSearchStopped(int)} will be
- * called with reason code {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}.
- * On failure, {@link BluetoothLeBroadcastAssistant.Callback#onSearchStopFailed(int)} will be
- * called with reason code
+ * <p>On success, {@link BluetoothLeBroadcastAssistant.Callback#onSearchStopped(int)} will be
+ * called with reason code {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}. On failure,
+ * {@link BluetoothLeBroadcastAssistant.Callback#onSearchStopFailed(int)} will be called with
+ * reason code
*
* @throws IllegalStateException if callback was not registered
*/
@@ -245,8 +283,8 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
* Get information about all Broadcast Sources that a Broadcast Sink knows about.
*
* @param sink Broadcast Sink from which to get all Broadcast Sources
- * @return the list of Broadcast Receive State {@link BluetoothLeBroadcastReceiveState}
- * stored in the Broadcast Sink
+ * @return the list of Broadcast Receive State {@link BluetoothLeBroadcastReceiveState} stored
+ * in the Broadcast Sink
* @throws NullPointerException when <var>sink</var> is null
*/
public @NonNull List<BluetoothLeBroadcastReceiveState> getAllSources(
@@ -261,24 +299,50 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
return mService.getAllSources(sink);
}
- public void registerServiceCallBack(@NonNull @CallbackExecutor Executor executor,
+ /**
+ * Register Broadcast Assistant Callbacks to track its state and receivers
+ *
+ * @param executor Executor object for callback
+ * @param callback Callback object to be registered
+ */
+ public void registerServiceCallBack(
+ @NonNull @CallbackExecutor Executor executor,
@NonNull BluetoothLeBroadcastAssistant.Callback callback) {
if (mService == null) {
- Log.d(TAG, "The BluetoothLeBroadcast is null.");
+ Log.d(
+ TAG,
+ "registerServiceCallBack failed, the BluetoothLeBroadcastAssistant is null.");
+ mCachedCallbackExecutorMap.putIfAbsent(callback, executor);
return;
}
- mService.registerCallback(executor, callback);
+ try {
+ mService.registerCallback(executor, callback);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "registerServiceCallBack failed. " + e.getMessage());
+ }
}
+ /**
+ * Unregister previously registered Broadcast Assistant Callbacks
+ *
+ * @param callback Callback object to be unregistered
+ */
public void unregisterServiceCallBack(
@NonNull BluetoothLeBroadcastAssistant.Callback callback) {
+ mCachedCallbackExecutorMap.remove(callback);
if (mService == null) {
- Log.d(TAG, "The BluetoothLeBroadcast is null.");
+ Log.d(
+ TAG,
+ "unregisterServiceCallBack failed, the BluetoothLeBroadcastAssistant is null.");
return;
}
- mService.unregisterCallback(callback);
+ try {
+ mService.unregisterCallback(callback);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "unregisterServiceCallBack failed. " + e.getMessage());
+ }
}
public boolean isProfileReady() {
@@ -310,9 +374,11 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
return new ArrayList<BluetoothDevice>(0);
}
return mService.getDevicesMatchingConnectionStates(
- new int[]{BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_CONNECTING,
- BluetoothProfile.STATE_DISCONNECTING});
+ new int[] {
+ BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING
+ });
}
public boolean isEnabled(BluetoothDevice device) {
@@ -373,9 +439,8 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
}
if (mService != null) {
try {
- BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
- BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT,
- mService);
+ BluetoothAdapter.getDefaultAdapter()
+ .closeProfileProxy(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, mService);
mService = null;
} catch (Throwable t) {
Log.w(TAG, "Error cleaning up LeAudio proxy", t);
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/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
index 914e5f2c17bf..fd04b5ee0d9c 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -51,6 +51,7 @@ object ComposeFacade : BaseComposeFacade {
activity: ComponentActivity,
viewModel: BaseCommunalViewModel,
onOpenWidgetPicker: () -> Unit,
+ onEditDone: () -> Unit,
) {
throwComposeUnavailableError()
}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
index 59bd95bd9027..5055ee1d73f6 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -66,12 +66,14 @@ object ComposeFacade : BaseComposeFacade {
activity: ComponentActivity,
viewModel: BaseCommunalViewModel,
onOpenWidgetPicker: () -> Unit,
+ onEditDone: () -> Unit,
) {
activity.setContent {
PlatformTheme {
CommunalHub(
viewModel = viewModel,
onOpenWidgetPicker = onOpenWidgetPicker,
+ onEditDone = onEditDone,
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index e8ecd3a66186..2a9cf0fdc507 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -25,10 +25,12 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
@@ -36,23 +38,41 @@ import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
-import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Edit
+import androidx.compose.material.icons.outlined.Delete
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonColors
+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.OutlinedButton
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.layout.positionInWindow
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
+import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
@@ -66,21 +86,38 @@ fun CommunalHub(
modifier: Modifier = Modifier,
viewModel: BaseCommunalViewModel,
onOpenWidgetPicker: (() -> Unit)? = null,
+ onEditDone: (() -> Unit)? = null,
) {
val communalContent by viewModel.communalContent.collectAsState(initial = emptyList())
+ var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
+ var toolbarSize: IntSize? by remember { mutableStateOf(null) }
+ var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
+ var isDraggingToRemove by remember { mutableStateOf(false) }
+
Box(
modifier = modifier.fillMaxSize().background(Color.White),
) {
CommunalHubLazyGrid(
- modifier = Modifier.height(Dimensions.GridHeight).align(Alignment.CenterStart),
+ modifier = Modifier.align(Alignment.CenterStart),
communalContent = communalContent,
- isEditMode = viewModel.isEditMode,
viewModel = viewModel,
- )
- if (viewModel.isEditMode && onOpenWidgetPicker != null) {
- IconButton(onClick = onOpenWidgetPicker) {
- Icon(Icons.Default.Add, stringResource(R.string.hub_mode_add_widget_button_text))
+ contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize),
+ setGridCoordinates = { gridCoordinates = it },
+ updateDragPositionForRemove = {
+ isDraggingToRemove =
+ checkForDraggingToRemove(it, removeButtonCoordinates, gridCoordinates)
+ isDraggingToRemove
}
+ )
+
+ if (viewModel.isEditMode && onOpenWidgetPicker != null && onEditDone != null) {
+ Toolbar(
+ isDraggingToRemove = isDraggingToRemove,
+ setToolbarSize = { toolbarSize = it },
+ setRemoveButtonCoordinates = { removeButtonCoordinates = it },
+ onEditDone = onEditDone,
+ onOpenWidgetPicker = onOpenWidgetPicker,
+ )
} else {
IconButton(onClick = viewModel::onOpenWidgetEditor) {
Icon(Icons.Default.Edit, stringResource(R.string.button_to_open_widget_editor))
@@ -103,25 +140,38 @@ fun CommunalHub(
@Composable
private fun CommunalHubLazyGrid(
communalContent: List<CommunalContentModel>,
- isEditMode: Boolean,
viewModel: BaseCommunalViewModel,
modifier: Modifier = Modifier,
+ contentPadding: PaddingValues,
+ setGridCoordinates: (coordinates: LayoutCoordinates) -> Unit,
+ updateDragPositionForRemove: (offset: Offset) -> Boolean,
) {
var gridModifier = modifier
val gridState = rememberLazyGridState()
var list = communalContent
var dragDropState: GridDragDropState? = null
- if (isEditMode && viewModel is CommunalEditModeViewModel) {
+ if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) {
val contentListState = rememberContentListState(communalContent, viewModel)
list = contentListState.list
- dragDropState = rememberGridDragDropState(gridState, contentListState)
- gridModifier = gridModifier.dragContainer(dragDropState)
+ dragDropState =
+ rememberGridDragDropState(
+ gridState = gridState,
+ contentListState = contentListState,
+ updateDragPositionForRemove = updateDragPositionForRemove
+ )
+ gridModifier =
+ gridModifier
+ .fillMaxSize()
+ .dragContainer(dragDropState, beforeContentPadding(contentPadding))
+ .onGloballyPositioned { setGridCoordinates(it) }
+ } else {
+ gridModifier = gridModifier.height(Dimensions.GridHeight)
}
LazyHorizontalGrid(
modifier = gridModifier,
state = gridState,
rows = GridCells.Fixed(CommunalContentSize.FULL.span),
- contentPadding = PaddingValues(horizontal = Dimensions.Spacing),
+ contentPadding = contentPadding,
horizontalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
verticalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
) {
@@ -130,19 +180,18 @@ private fun CommunalHubLazyGrid(
key = { index -> list[index].key },
span = { index -> GridItemSpan(list[index].size.span) },
) { index ->
- val cardModifier = Modifier.fillMaxHeight().width(Dimensions.CardWidth)
+ val cardModifier = Modifier.width(Dimensions.CardWidth)
val size =
SizeF(
Dimensions.CardWidth.value,
list[index].size.dp().value,
)
- if (isEditMode && dragDropState != null) {
+ if (viewModel.isEditMode && dragDropState != null) {
DraggableItem(dragDropState = dragDropState, enabled = true, index = index) {
isDragging ->
val elevation by animateDpAsState(if (isDragging) 4.dp else 1.dp)
CommunalContent(
modifier = cardModifier,
- deleteOnClick = viewModel::onDeleteWidget,
elevation = elevation,
model = list[index],
viewModel = viewModel,
@@ -161,6 +210,95 @@ private fun CommunalHubLazyGrid(
}
}
+/**
+ * Toolbar that contains action buttons to
+ * 1) open the widget picker
+ * 2) remove a widget from the grid and
+ * 3) exit the edit mode.
+ */
+@Composable
+private fun Toolbar(
+ isDraggingToRemove: Boolean,
+ setToolbarSize: (toolbarSize: IntSize) -> Unit,
+ setRemoveButtonCoordinates: (coordinates: LayoutCoordinates) -> Unit,
+ onOpenWidgetPicker: () -> Unit,
+ onEditDone: () -> Unit,
+) {
+ Row(
+ modifier =
+ Modifier.fillMaxWidth()
+ .padding(
+ top = Dimensions.ToolbarPaddingTop,
+ start = Dimensions.ToolbarPaddingHorizontal,
+ end = Dimensions.ToolbarPaddingHorizontal,
+ )
+ .onSizeChanged { setToolbarSize(it) },
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ val buttonContentPadding =
+ PaddingValues(
+ vertical = Dimensions.ToolbarButtonPaddingVertical,
+ horizontal = Dimensions.ToolbarButtonPaddingHorizontal,
+ )
+ val spacerModifier = Modifier.width(Dimensions.ToolbarButtonSpaceBetween)
+ Button(
+ onClick = onOpenWidgetPicker,
+ colors = filledSecondaryButtonColors(),
+ contentPadding = buttonContentPadding
+ ) {
+ Icon(Icons.Default.Add, stringResource(R.string.button_to_open_widget_editor))
+ Spacer(spacerModifier)
+ Text(
+ text = stringResource(R.string.hub_mode_add_widget_button_text),
+ )
+ }
+
+ val buttonColors =
+ if (isDraggingToRemove) filledButtonColors() else ButtonDefaults.outlinedButtonColors()
+ OutlinedButton(
+ onClick = {},
+ colors = buttonColors,
+ contentPadding = buttonContentPadding,
+ modifier = Modifier.onGloballyPositioned { setRemoveButtonCoordinates(it) },
+ ) {
+ Icon(Icons.Outlined.Delete, stringResource(R.string.button_to_open_widget_editor))
+ Spacer(spacerModifier)
+ Text(
+ text = stringResource(R.string.button_to_remove_widget),
+ )
+ }
+
+ Button(
+ onClick = onEditDone,
+ colors = filledButtonColors(),
+ contentPadding = buttonContentPadding
+ ) {
+ Text(
+ text = stringResource(R.string.hub_mode_editing_exit_button_text),
+ )
+ }
+ }
+}
+
+@Composable
+private fun filledButtonColors(): ButtonColors {
+ val colors = LocalAndroidColorScheme.current
+ return ButtonDefaults.buttonColors(
+ containerColor = colors.primary,
+ contentColor = colors.onPrimary,
+ )
+}
+
+@Composable
+private fun filledSecondaryButtonColors(): ButtonColors {
+ val colors = LocalAndroidColorScheme.current
+ return ButtonDefaults.buttonColors(
+ containerColor = colors.secondary,
+ contentColor = colors.onSecondary,
+ )
+}
+
@Composable
private fun CommunalContent(
model: CommunalContentModel,
@@ -168,11 +306,9 @@ private fun CommunalContent(
size: SizeF,
modifier: Modifier = Modifier,
elevation: Dp = 0.dp,
- deleteOnClick: ((id: Int) -> Unit)? = null,
) {
when (model) {
- is CommunalContentModel.Widget ->
- WidgetContent(model, size, elevation, deleteOnClick, modifier)
+ is CommunalContentModel.Widget -> WidgetContent(model, size, elevation, modifier)
is CommunalContentModel.Smartspace -> SmartspaceContent(model, modifier)
is CommunalContentModel.Tutorial -> TutorialContent(modifier)
is CommunalContentModel.Umo -> Umo(viewModel, modifier)
@@ -184,19 +320,12 @@ private fun WidgetContent(
model: CommunalContentModel.Widget,
size: SizeF,
elevation: Dp,
- deleteOnClick: ((id: Int) -> Unit)?,
modifier: Modifier = Modifier,
) {
- // TODO(b/309009246): update background color
Card(
- modifier = modifier.fillMaxSize().background(Color.White),
+ modifier = modifier.height(size.height.dp),
elevation = CardDefaults.cardElevation(draggedElevation = elevation),
) {
- if (deleteOnClick != null) {
- IconButton(onClick = { deleteOnClick(model.appWidgetId) }) {
- Icon(Icons.Default.Close, stringResource(R.string.button_to_remove_widget))
- }
- }
AndroidView(
modifier = modifier,
factory = { context ->
@@ -249,6 +378,60 @@ private fun Umo(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier)
)
}
+/**
+ * Returns the `contentPadding` of the grid. Use the vertical padding to push the grid content area
+ * below the toolbar and let the grid take the max size. This ensures the item can be dragged
+ * outside the grid over the toolbar, without part of it getting clipped by the container.
+ */
+@Composable
+private fun gridContentPadding(isEditMode: Boolean, toolbarSize: IntSize?): PaddingValues {
+ if (!isEditMode || toolbarSize == null) {
+ return PaddingValues(horizontal = Dimensions.Spacing)
+ }
+ val configuration = LocalConfiguration.current
+ val density = LocalDensity.current
+ val screenHeight = configuration.screenHeightDp.dp
+ val toolbarHeight = with(density) { Dimensions.ToolbarPaddingTop + toolbarSize.height.toDp() }
+ val verticalPadding =
+ ((screenHeight - toolbarHeight - Dimensions.GridHeight) / 2).coerceAtLeast(
+ Dimensions.Spacing
+ )
+ return PaddingValues(
+ start = Dimensions.ToolbarPaddingHorizontal,
+ end = Dimensions.ToolbarPaddingHorizontal,
+ top = verticalPadding + toolbarHeight,
+ bottom = verticalPadding
+ )
+}
+
+@Composable
+private fun beforeContentPadding(paddingValues: PaddingValues): ContentPaddingInPx {
+ return with(LocalDensity.current) {
+ ContentPaddingInPx(
+ startPadding = paddingValues.calculateLeftPadding(LayoutDirection.Ltr).toPx(),
+ topPadding = paddingValues.calculateTopPadding().toPx()
+ )
+ }
+}
+
+/**
+ * Check whether the pointer position that the item is being dragged at is within the coordinates of
+ * the remove button in the toolbar. Returns true if the item is removable.
+ */
+private fun checkForDraggingToRemove(
+ offset: Offset,
+ removeButtonCoordinates: LayoutCoordinates?,
+ gridCoordinates: LayoutCoordinates?,
+): Boolean {
+ if (removeButtonCoordinates == null || gridCoordinates == null) {
+ return false
+ }
+ val pointer = gridCoordinates.positionInWindow() + offset
+ val removeButton = removeButtonCoordinates.positionInWindow()
+ return pointer.x in removeButton.x..removeButton.x + removeButtonCoordinates.size.width &&
+ pointer.y in removeButton.y..removeButton.y + removeButtonCoordinates.size.height
+}
+
private fun CommunalContentSize.dp(): Dp {
return when (this) {
CommunalContentSize.FULL -> Dimensions.CardHeightFull
@@ -257,6 +440,8 @@ private fun CommunalContentSize.dp(): Dp {
}
}
+data class ContentPaddingInPx(val startPadding: Float, val topPadding: Float)
+
object Dimensions {
val CardWidth = 464.dp
val CardHeightFull = 630.dp
@@ -264,4 +449,11 @@ object Dimensions {
val CardHeightThird = 199.dp
val GridHeight = CardHeightFull
val Spacing = 16.dp
+
+ // The sizing/padding of the toolbar in glanceable hub edit mode
+ val ToolbarPaddingTop = 27.dp
+ val ToolbarPaddingHorizontal = 16.dp
+ val ToolbarButtonPaddingHorizontal = 24.dp
+ val ToolbarButtonPaddingVertical = 16.dp
+ val ToolbarButtonSpaceBetween = 8.dp
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
index 6cfa2f233f46..5451d0550095 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
@@ -48,12 +48,18 @@ import kotlinx.coroutines.launch
@Composable
fun rememberGridDragDropState(
gridState: LazyGridState,
- contentListState: ContentListState
+ contentListState: ContentListState,
+ updateDragPositionForRemove: (offset: Offset) -> Boolean,
): GridDragDropState {
val scope = rememberCoroutineScope()
val state =
remember(gridState, contentListState) {
- GridDragDropState(state = gridState, contentListState = contentListState, scope = scope)
+ GridDragDropState(
+ state = gridState,
+ contentListState = contentListState,
+ scope = scope,
+ updateDragPositionForRemove = updateDragPositionForRemove
+ )
}
LaunchedEffect(state) {
while (true) {
@@ -67,23 +73,30 @@ fun rememberGridDragDropState(
/**
* Handles drag and drop cards in the glanceable hub. While dragging to move, other items that are
* affected will dynamically get positioned and the state is tracked by [ContentListState]. When
- * dragging to remove, affected cards will be moved and [ContentListState.onRemove] is called to
- * remove the dragged item. On dragging ends, call [ContentListState.onSaveList] to persist the
- * change.
+ * dragging to remove, affected cards will be moved and [updateDragPositionForRemove] is called to
+ * check whether the dragged item can be removed. On dragging ends, call [ContentListState.onRemove]
+ * to remove the dragged item if condition met and call [ContentListState.onSaveList] to persist any
+ * change in ordering.
*/
class GridDragDropState
internal constructor(
private val state: LazyGridState,
private val contentListState: ContentListState,
private val scope: CoroutineScope,
+ private val updateDragPositionForRemove: (offset: Offset) -> Boolean
) {
var draggingItemIndex by mutableStateOf<Int?>(null)
private set
+ var isDraggingToRemove by mutableStateOf(false)
+ private set
+
internal val scrollChannel = Channel<Float>()
private var draggingItemDraggedDelta by mutableStateOf(Offset.Zero)
private var draggingItemInitialOffset by mutableStateOf(Offset.Zero)
+ private var dragStartPointerOffset by mutableStateOf(Offset.Zero)
+
internal val draggingItemOffset: Offset
get() =
draggingItemLayoutInfo?.let { item ->
@@ -94,27 +107,36 @@ internal constructor(
private val draggingItemLayoutInfo: LazyGridItemInfo?
get() = state.layoutInfo.visibleItemsInfo.firstOrNull { it.index == draggingItemIndex }
- internal fun onDragStart(offset: Offset) {
+ internal fun onDragStart(offset: Offset, contentOffset: Offset) {
state.layoutInfo.visibleItemsInfo
.firstOrNull { item ->
+ // grid item offset is based off grid content container so we need to deduct
+ // before content padding from the initial pointer position
item.isEditable &&
- offset.x.toInt() in item.offset.x..item.offsetEnd.x &&
- offset.y.toInt() in item.offset.y..item.offsetEnd.y
+ (offset.x - contentOffset.x).toInt() in item.offset.x..item.offsetEnd.x &&
+ (offset.y - contentOffset.y).toInt() in item.offset.y..item.offsetEnd.y
}
?.apply {
+ dragStartPointerOffset = offset - this.offset.toOffset()
draggingItemIndex = index
draggingItemInitialOffset = this.offset.toOffset()
}
}
internal fun onDragInterrupted() {
- if (draggingItemIndex != null) {
+ draggingItemIndex?.let {
+ if (isDraggingToRemove) {
+ contentListState.onRemove(it)
+ isDraggingToRemove = false
+ updateDragPositionForRemove(Offset.Zero)
+ }
// persist list editing changes on dragging ends
contentListState.onSaveList()
draggingItemIndex = null
}
draggingItemDraggedDelta = Offset.Zero
draggingItemInitialOffset = Offset.Zero
+ dragStartPointerOffset = Offset.Zero
}
internal fun onDrag(offset: Offset) {
@@ -152,18 +174,13 @@ internal constructor(
contentListState.onMove(draggingItem.index, targetItem.index)
}
draggingItemIndex = targetItem.index
+ isDraggingToRemove = false
} else {
val overscroll = checkForOverscroll(startOffset, endOffset)
if (overscroll != 0f) {
scrollChannel.trySend(overscroll)
}
- val removeOffset = checkForRemove(startOffset)
- if (removeOffset != 0f) {
- draggingItemIndex?.let {
- contentListState.onRemove(it)
- draggingItemIndex = null
- }
- }
+ isDraggingToRemove = checkForRemove(startOffset)
}
}
@@ -185,14 +202,11 @@ internal constructor(
}
}
- // TODO(b/309968801): a temporary solution to decide whether to remove card when it's dragged up
- // and out of grid. Once we have a taskbar, calculate the intersection of the dragged item with
- // the Remove button.
- private fun checkForRemove(startOffset: Offset): Float {
+ /** Calls the callback with the updated drag position and returns whether to remove the item. */
+ private fun checkForRemove(startOffset: Offset): Boolean {
return if (draggingItemDraggedDelta.y < 0)
- (startOffset.y + Dimensions.CardHeightHalf.value - state.layoutInfo.viewportStartOffset)
- .coerceAtMost(0f)
- else 0f
+ updateDragPositionForRemove(startOffset + dragStartPointerOffset)
+ else false
}
}
@@ -204,14 +218,22 @@ private operator fun Offset.plus(size: Size): Offset {
return Offset(x + size.width, y + size.height)
}
-fun Modifier.dragContainer(dragDropState: GridDragDropState): Modifier {
- return pointerInput(dragDropState) {
+fun Modifier.dragContainer(
+ dragDropState: GridDragDropState,
+ beforeContentPadding: ContentPaddingInPx
+): Modifier {
+ return pointerInput(dragDropState, beforeContentPadding) {
detectDragGesturesAfterLongPress(
onDrag = { change, offset ->
change.consume()
dragDropState.onDrag(offset = offset)
},
- onDragStart = { offset -> dragDropState.onDragStart(offset) },
+ onDragStart = { offset ->
+ dragDropState.onDragStart(
+ offset,
+ Offset(beforeContentPadding.startPadding, beforeContentPadding.topPadding)
+ )
+ },
onDragEnd = { dragDropState.onDragInterrupted() },
onDragCancel = { dragDropState.onDragInterrupted() }
)
@@ -237,6 +259,7 @@ fun LazyGridItemScope.DraggableItem(
Modifier.zIndex(1f).graphicsLayer {
translationX = dragDropState.draggingItemOffset.x
translationY = dragDropState.draggingItemOffset.y
+ alpha = if (dragDropState.isDraggingToRemove) 0.5f else 1f
}
} else {
Modifier.animateItemPlacement()
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 009f8bb38e61..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,12 +174,8 @@ private fun <T> computeValue(
lerp: (T, T, Float) -> T,
canOverflow: Boolean,
): T {
- val state = layoutImpl.state.transitionState
- if (
- state !is TransitionState.Transition ||
- state.fromScene == state.toScene ||
- !layoutImpl.isTransitionReady(state)
- ) {
+ val transition = layoutImpl.state.currentTransition
+ if (transition == null || !layoutImpl.isTransitionReady(transition)) {
return sharedValue.value
}
@@ -195,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 199832bc4ab6..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,50 +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 -> {
- if (state.toScene == state.fromScene) {
- // Same as idle.
- animate(layoutImpl, target)
- return
- }
-
// 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
@@ -95,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) {
@@ -125,7 +117,6 @@ private fun CoroutineScope.animate(
currentScene = target,
isInitiatedByUserInput = isUserInput,
isUserInputOngoing = false,
- animatable = animatable,
)
} else {
OneOffTransition(
@@ -134,32 +125,46 @@ 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)
}
}
private class OneOffTransition(
- override val fromScene: SceneKey,
- override val toScene: SceneKey,
+ fromScene: SceneKey,
+ toScene: SceneKey,
override val currentScene: SceneKey,
override val isInitiatedByUserInput: Boolean,
override val isUserInputOngoing: Boolean,
- private val animatable: Animatable<Float, AnimationVector1D>,
-) : TransitionState.Transition {
+) : 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 31604a6817f0..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,27 +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 ||
- state.fromScene == state.toScene ||
- !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,
@@ -332,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) {
@@ -372,13 +368,9 @@ private fun isElementOpaque(
scene: Scene,
sceneValues: Element.TargetValues,
): Boolean {
- val state = layoutImpl.state.transitionState
-
- if (state !is TransitionState.Transition || state.fromScene == state.toScene) {
- 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
@@ -386,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]
@@ -396,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
}
/**
@@ -608,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 || state.fromScene == state.toScene) {
- // 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]
@@ -639,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).
@@ -676,7 +659,7 @@ private inline fun <T> computeValue(
scene,
element,
sceneValues,
- state,
+ transition,
idleValue,
)
@@ -686,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 fa385d014ccb..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,21 +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
- if (fromScene == toScene) {
- check(fromScene == scene)
- return true
- }
+ 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)
@@ -185,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/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index 1b79dbdee510..983cff83ed57 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -73,17 +73,13 @@ fun SceneTransitionLayoutState.observableTransitionState(): Flow<ObservableTrans
when (val state = transitionState) {
is TransitionState.Idle -> ObservableTransitionState.Idle(state.currentScene)
is TransitionState.Transition -> {
- if (state.fromScene == state.toScene) {
- ObservableTransitionState.Idle(state.currentScene)
- } else {
- ObservableTransitionState.Transition(
- fromScene = state.fromScene,
- toScene = state.toScene,
- progress = snapshotFlow { state.progress },
- isInitiatedByUserInput = state.isInitiatedByUserInput,
- isUserInputOngoing = snapshotFlow { state.isUserInputOngoing },
- )
- }
+ ObservableTransitionState.Transition(
+ fromScene = state.fromScene,
+ toScene = state.toScene,
+ progress = snapshotFlow { state.progress },
+ isInitiatedByUserInput = state.isInitiatedByUserInput,
+ isUserInputOngoing = snapshotFlow { state.isUserInputOngoing },
+ )
}
}
}
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 03f37d0c9bda..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,39 +41,37 @@ 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
+ private var _swipeTransition: SwipeTransition? = null
+ internal var swipeTransition: SwipeTransition
+ get() = _swipeTransition ?: error("SwipeTransition needs to be initialized")
set(value) {
- layoutImpl.state.transitionState = value
+ _swipeTransition = value
}
- internal var swipeTransition: SwipeTransition = SwipeTransition(currentScene, currentScene, 1f)
- private set
-
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
@@ -82,34 +80,34 @@ internal class SceneGestureHandler(
private var actionDownOrRight: UserAction? = null
private var actionUpOrLeftNoEdge: UserAction? = null
private var actionDownOrRightNoEdge: UserAction? = null
+ private var upOrLeftScene: SceneKey? = null
+ private var downOrRightScene: SceneKey? = null
internal fun onDragStarted(pointersDown: Int, startedPosition: Offset?, overSlop: Float) {
if (isDrivingTransition) {
// This [transition] was already driving the animation: simply take over it.
// Stop animating and start from where the current offset.
swipeTransition.cancelOffsetAnimation()
+ updateTargetScenes(swipeTransition._fromScene)
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)
- if (fromScene.upOrLeft() == null && fromScene.downOrRight() == null) {
- return
- }
-
- val (targetScene, distance) = fromScene.findTargetSceneAndDistance(overSlop)
+ val (targetScene, distance) =
+ findTargetSceneAndDistance(fromScene, overSlop, updateScenes = true) ?: return
updateTransition(SwipeTransition(fromScene, targetScene, distance), force = true)
}
@@ -179,16 +177,21 @@ internal class SceneGestureHandler(
val (fromScene, acceleratedOffset) =
computeFromSceneConsideringAcceleratedSwipe(swipeTransition)
- swipeTransition.dragOffset += acceleratedOffset
- // Compute the target scene depending on the current offset.
+ val isNewFromScene = fromScene.key != swipeTransition.fromScene
val (targetScene, distance) =
- fromScene.findTargetSceneAndDistance(swipeTransition.dragOffset)
+ findTargetSceneAndDistance(
+ fromScene,
+ swipeTransition.dragOffset,
+ updateScenes = isNewFromScene,
+ )
+ ?: run {
+ onDragStopped(delta, true)
+ return
+ }
+ swipeTransition.dragOffset += acceleratedOffset
- // TODO(b/290184746): support long scroll A => B => C? especially for non fullscreen scenes
- if (
- fromScene.key != swipeTransition.fromScene || targetScene.key != swipeTransition.toScene
- ) {
+ if (isNewFromScene || targetScene.key != swipeTransition.toScene) {
updateTransition(
SwipeTransition(fromScene, targetScene, distance).apply {
this.dragOffset = swipeTransition.dragOffset
@@ -197,6 +200,11 @@ internal class SceneGestureHandler(
}
}
+ private fun updateTargetScenes(fromScene: Scene) {
+ upOrLeftScene = fromScene.upOrLeft()
+ downOrRightScene = fromScene.downOrRight()
+ }
+
/**
* Change fromScene in the case where the user quickly swiped multiple times in the same
* direction to accelerate the transition from A => B then B => C.
@@ -214,37 +222,71 @@ internal class SceneGestureHandler(
val absoluteDistance = swipeTransition.distance.absoluteValue
// If the swipe was not committed, don't do anything.
- if (fromScene == toScene || swipeTransition._currentScene != toScene) {
+ if (swipeTransition._currentScene != toScene) {
return Pair(fromScene, 0f)
}
// If the offset is past the distance then let's change fromScene so that the user can swipe
// to the next screen or go back to the previous one.
val offset = swipeTransition.dragOffset
- return if (offset <= -absoluteDistance && fromScene.upOrLeft() == toScene.key) {
+ return if (offset <= -absoluteDistance && upOrLeftScene == toScene.key) {
Pair(toScene, absoluteDistance)
- } else if (offset >= absoluteDistance && fromScene.downOrRight() == toScene.key) {
+ } else if (offset >= absoluteDistance && downOrRightScene == toScene.key) {
Pair(toScene, -absoluteDistance)
} else {
Pair(fromScene, 0f)
}
}
- // TODO(b/290184746): there are two bugs here:
- // 1. if both upOrLeft and downOrRight become `null` during a transition this will crash
- // 2. if one of them changes during a transition, the transition will jump cut to the new target
- private inline fun Scene.findTargetSceneAndDistance(
- directionOffset: Float
- ): Pair<Scene, Float> {
- val upOrLeft = upOrLeft()
- val downOrRight = downOrRight()
- val absoluteDistance = getAbsoluteDistance()
+ /**
+ * Returns the target scene and distance from [fromScene] in the direction [directionOffset].
+ *
+ * @param fromScene the scene from which we look for the target
+ * @param directionOffset signed float that indicates the direction. Positive is down or right
+ * negative is up or left.
+ * @param updateScenes whether the target scenes should be updated to the current values held in
+ * the Scenes map. Usually we don't want to update them while doing a drag, because this could
+ * change the target scene (jump cutting) to a different scene, when some system state changed
+ * the targets the background. However, an update is needed any time we calculate the targets
+ * for a new fromScene.
+ * @return null when there are no targets in either direction. If one direction is null and you
+ * drag into the null direction this function will return the opposite direction, assuming
+ * that the users intention is to start the drag into the other direction eventually. If
+ * [directionOffset] is 0f and both direction are available, it will default to
+ * [upOrLeftScene].
+ */
+ private inline fun findTargetSceneAndDistance(
+ fromScene: Scene,
+ directionOffset: Float,
+ updateScenes: Boolean,
+ ): Pair<Scene, Float>? {
+ if (updateScenes) updateTargetScenes(fromScene)
+ val absoluteDistance = fromScene.getAbsoluteDistance()
// Compute the target scene depending on the current offset.
- return if ((directionOffset < 0f && upOrLeft != null) || downOrRight == null) {
- Pair(layoutImpl.scene(upOrLeft!!), -absoluteDistance)
- } else {
- Pair(layoutImpl.scene(downOrRight), absoluteDistance)
+ return when {
+ upOrLeftScene == null && downOrRightScene == null -> null
+ (directionOffset < 0f && upOrLeftScene != null) || downOrRightScene == null ->
+ Pair(layoutImpl.scene(upOrLeftScene!!), -absoluteDistance)
+ else -> Pair(layoutImpl.scene(downOrRightScene!!), absoluteDistance)
+ }
+ }
+
+ /**
+ * A strict version of [findTargetSceneAndDistance] that will return null when there is no Scene
+ * in [directionOffset] direction
+ */
+ private inline fun findTargetSceneAndDistanceStrict(
+ fromScene: Scene,
+ directionOffset: Float,
+ ): Pair<Scene, Float>? {
+ val absoluteDistance = fromScene.getAbsoluteDistance()
+ return when {
+ directionOffset > 0f ->
+ upOrLeftScene?.let { Pair(layoutImpl.scene(it), -absoluteDistance) }
+ directionOffset < 0f ->
+ downOrRightScene?.let { Pair(layoutImpl.scene(it), absoluteDistance) }
+ else -> null
}
}
@@ -311,20 +353,21 @@ internal class SceneGestureHandler(
val startFromIdlePosition = swipeTransition.dragOffset == 0f
if (startFromIdlePosition) {
- // If there is a next scene, we start the overscroll animation.
- val (targetScene, distance) = fromScene.findTargetSceneAndDistance(velocity)
- val isValidTarget = distance != 0f && targetScene.key != fromScene.key
- if (isValidTarget) {
- updateTransition(
- SwipeTransition(fromScene, targetScene, distance).apply {
- _currentScene = swipeTransition._currentScene
+ // If there is a target scene, we start the overscroll animation.
+ val (targetScene, distance) =
+ findTargetSceneAndDistanceStrict(fromScene, velocity)
+ ?: run {
+ // We will not animate
+ layoutState.finishTransition(swipeTransition, idleScene = fromScene.key)
+ return
}
- )
- animateTo(targetScene = fromScene, targetOffset = 0f)
- } else {
- // We will not animate
- transitionState = TransitionState.Idle(fromScene.key)
- }
+
+ updateTransition(
+ SwipeTransition(fromScene, targetScene, distance).apply {
+ _currentScene = swipeTransition._currentScene
+ }
+ )
+ animateTo(targetScene = fromScene, targetOffset = 0f)
} else {
// We were between two scenes: animate to the initial scene.
animateTo(targetScene = fromScene, targetOffset = 0f)
@@ -390,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)
}
}
}
@@ -410,15 +446,11 @@ internal class SceneGestureHandler(
* above or to the left of [toScene].
*/
val distance: Float
- ) : TransitionState.Transition {
+ ) : TransitionState.Transition(_fromScene.key, _toScene.key) {
var _currentScene by mutableStateOf(_fromScene)
override val currentScene: SceneKey
get() = _currentScene.key
- override val fromScene: SceneKey = _fromScene.key
-
- override val toScene: SceneKey = _toScene.key
-
override val progress: Float
get() {
val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
@@ -494,10 +526,14 @@ private class SceneDraggableHandler(
}
internal class SceneNestedScrollHandler(
- private val gestureHandler: SceneGestureHandler,
- private val topOrLeftBehavior: NestedScrollBehavior,
- private val bottomOrRightBehavior: NestedScrollBehavior,
+ 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 {
@@ -508,7 +544,7 @@ internal class SceneNestedScrollHandler(
val actionUpOrLeft =
Swipe(
direction =
- when (gestureHandler.orientation) {
+ when (orientation) {
Orientation.Horizontal -> SwipeDirection.Left
Orientation.Vertical -> SwipeDirection.Up
},
@@ -518,7 +554,7 @@ internal class SceneNestedScrollHandler(
val actionDownOrRight =
Swipe(
direction =
- when (gestureHandler.orientation) {
+ when (orientation) {
Orientation.Horizontal -> SwipeDirection.Right
Orientation.Vertical -> SwipeDirection.Down
},
@@ -526,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]
@@ -537,7 +573,7 @@ internal class SceneNestedScrollHandler(
}
return PriorityNestedScrollConnection(
- orientation = gestureHandler.orientation,
+ orientation = orientation,
canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
canChangeScene = offsetBeforeStart == 0f
@@ -545,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
@@ -554,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 02ddccbc051b..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 || state.fromScene == state.toScene) {
+ 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,16 +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) ||
- state.fromScene == state.toScene
- ) {
- 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 f48e9147eef4..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,36 +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
-
- // TODO(b/310915136): Remove this check.
- if (transition.fromScene == transition.toScene) {
- 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
@@ -71,32 +67,77 @@ sealed interface TransitionState {
/** No transition/animation is currently running. */
data class Idle(override val currentScene: SceneKey) : TransitionState
- /**
- * There is a transition animating between two scenes.
- *
- * Important note: [fromScene] and [toScene] might be the same, in which case this [Transition]
- * should be treated the same as [Idle]. This is designed on purpose so that a [Transition] can
- * be started without knowing in advance where it is transitioning to, making the logic of
- * [swipeToScene] easier to reason about.
- */
- interface Transition : TransitionState {
- /** The scene this transition is starting from. */
- val fromScene: SceneKey
+ /** There is a transition animating between two scenes. */
+ abstract class Transition(
+ /** The scene this transition is starting from. Can't be the same as toScene */
+ val fromScene: SceneKey,
- /** The scene this transition is going to. */
+ /** The scene this transition is going to. Can't be the same as fromScene */
val toScene: SceneKey
+ ) : TransitionState {
+
+ init {
+ check(fromScene != toScene)
+ }
/**
* The progress of the transition. This is usually in the `[0; 1]` range, but it can also be
* less than `0` or greater than `1` when using transitions with a spring AnimationSpec or
* when flinging quickly during a swipe gesture.
*/
- val progress: Float
+ abstract val progress: Float
/** Whether the transition was triggered by user input rather than being programmatic. */
- val isInitiatedByUserInput: Boolean
+ abstract val isInitiatedByUserInput: Boolean
/** Whether user input is currently driving the transition. */
- val isUserInputOngoing: Boolean
+ 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 34afc4c91d4c..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,19 +55,25 @@ 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)
+
+ val mutableUserActionsB: MutableMap<UserAction, SceneKey> =
+ mutableMapOf(Swipe.Up to SceneC, Swipe.Down to SceneA)
private val scenesBuilder: SceneTransitionLayoutScope.() -> Unit = {
scene(
key = SceneA,
- userActions = mapOf(Swipe.Up to SceneB, Swipe.Down to SceneC),
+ userActions = mutableUserActionsA,
) {
Text("SceneA")
}
scene(
key = SceneB,
- userActions = mapOf(Swipe.Up to SceneC, Swipe.Down to SceneA),
+ userActions = mutableUserActionsB,
) {
Text("SceneB")
}
@@ -87,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,
)
@@ -412,6 +406,70 @@ class SceneGestureHandlerTest {
}
@Test
+ fun onAccelaratedScrollBothTargetsBecomeNull_settlesToIdle() = runGestureTest {
+ draggable.onDragStarted()
+ draggable.onDelta(up(0.2f))
+
+ draggable.onDelta(up(0.2f))
+ draggable.onDragStopped(velocity = -velocityThreshold)
+ assertTransition(currentScene = SceneB, fromScene = SceneA, toScene = SceneB)
+
+ mutableUserActionsA.remove(Swipe.Up)
+ mutableUserActionsA.remove(Swipe.Down)
+ mutableUserActionsB.remove(Swipe.Up)
+ mutableUserActionsB.remove(Swipe.Down)
+
+ // start accelaratedScroll and scroll over to B -> null
+ draggable.onDragStarted()
+ draggable.onDelta(up(0.5f))
+ draggable.onDelta(up(0.5f))
+
+ // here onDragStopped is already triggered, but subsequent onDelta/onDragStopped calls may
+ // still be called. Make sure that they don't crash or change the scene
+ draggable.onDelta(up(0.5f))
+ draggable.onDragStopped(0f)
+
+ advanceUntilIdle()
+ assertIdle(SceneB)
+
+ // These events can still come in after the animation has settled
+ draggable.onDelta(up(0.5f))
+ draggable.onDragStopped(0f)
+ assertIdle(SceneB)
+ }
+
+ @Test
+ fun onDragTargetsChanged_targetStaysTheSame() = runGestureTest {
+ draggable.onDragStarted(up(0.1f))
+ assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.1f)
+
+ mutableUserActionsA[Swipe.Up] = SceneC
+ draggable.onDelta(up(0.1f))
+ // target stays B even though UserActions changed
+ assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.2f)
+ draggable.onDragStopped(down(0.1f))
+ advanceUntilIdle()
+
+ // now target changed to C for new drag
+ draggable.onDragStarted(up(0.1f))
+ assertTransition(fromScene = SceneA, toScene = SceneC, progress = 0.1f)
+ }
+
+ @Test
+ fun onDragTargetsChanged_targetsChangeWhenStartingNewDrag() = runGestureTest {
+ draggable.onDragStarted(up(0.1f))
+ assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.1f)
+
+ mutableUserActionsA[Swipe.Up] = SceneC
+ draggable.onDelta(up(0.1f))
+ draggable.onDragStopped(down(0.1f))
+
+ // now target changed to C for new drag that started before previous drag settled to Idle
+ draggable.onDragStarted(up(0.1f))
+ assertTransition(fromScene = SceneA, toScene = SceneC, progress = 0.3f)
+ }
+
+ @Test
fun startGestureDuringAnimatingOffset_shouldImmediatelyStopTheAnimation() = runGestureTest {
draggable.onDragStarted()
assertTransition(currentScene = SceneA)
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 94c51ca50667..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
@@ -39,21 +39,9 @@ class SceneTransitionLayoutStateTest {
}
@Test
- fun isTransitioningTo_fromSceneEqualToToScene() {
- val state = SceneTransitionLayoutState(TestScenes.SceneA)
- state.transitionState = transition(from = TestScenes.SceneA, to = TestScenes.SceneA)
-
- assertThat(state.isTransitioning()).isFalse()
- assertThat(state.isTransitioning(from = TestScenes.SceneA)).isFalse()
- assertThat(state.isTransitioning(to = TestScenes.SceneB)).isFalse()
- assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB))
- .isFalse()
- }
-
- @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()
@@ -64,10 +52,8 @@ class SceneTransitionLayoutStateTest {
}
private fun transition(from: SceneKey, to: SceneKey): TransitionState.Transition {
- return object : TransitionState.Transition {
+ return object : TransitionState.Transition(from, to) {
override val currentScene: SceneKey = from
- override val fromScene: SceneKey = from
- override val toScene: SceneKey = to
override val progress: Float = 0f
override val isInitiatedByUserInput: Boolean = false
override val isUserInputOngoing: Boolean = false
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/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 16cfa2398fd5..1f8e29adc983 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -161,7 +161,7 @@ class CommunalInteractorTest : SysuiTestCase() {
whenever(target1.remoteViews).thenReturn(mock(RemoteViews::class.java))
val targets = listOf(target1, target2, target3)
- smartspaceRepository.setLockscreenSmartspaceTargets(targets)
+ smartspaceRepository.setCommunalSmartspaceTargets(targets)
val smartspaceContent by collectLastValue(underTest.smartspaceContent)
assertThat(smartspaceContent?.size).isEqualTo(1)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index 8896e6e64bd9..314dfdfd6f2a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -116,7 +116,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
whenever(target.smartspaceTargetId).thenReturn("target")
whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java))
- smartspaceRepository.setLockscreenSmartspaceTargets(listOf(target))
+ smartspaceRepository.setCommunalSmartspaceTargets(listOf(target))
// Media playing.
mediaRepository.mediaPlaying.value = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 7fbcae0d8986..8a71168324aa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -135,7 +135,7 @@ class CommunalViewModelTest : SysuiTestCase() {
whenever(target.smartspaceTargetId).thenReturn("target")
whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java))
- smartspaceRepository.setLockscreenSmartspaceTargets(listOf(target))
+ smartspaceRepository.setCommunalSmartspaceTargets(listOf(target))
// Media playing.
mediaRepository.mediaPlaying.value = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 45aca175657e..d6d5b23a311d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -827,7 +827,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
}
@Test
- fun isAuthenticatedIsResetToFalseWhenKeyguardIsGoingAway() =
+ fun isAuthenticatedIsResetToFalseWhenDeviceStartsGoingToSleep() =
testScope.runTest {
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
@@ -840,13 +840,13 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
assertThat(authenticated()).isTrue()
- keyguardRepository.setKeyguardGoingAway(true)
+ powerInteractor.setAsleepForTest()
assertThat(authenticated()).isFalse()
}
@Test
- fun isAuthenticatedIsResetToFalseWhenDeviceStartsGoingToSleep() =
+ fun isAuthenticatedIsResetToFalseWhenDeviceGoesToSleep() =
testScope.runTest {
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
@@ -865,7 +865,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
}
@Test
- fun isAuthenticatedIsResetToFalseWhenDeviceGoesToSleep() =
+ fun isAuthenticatedIsResetToFalseWhenUserIsSwitching() =
testScope.runTest {
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
@@ -878,13 +878,16 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
assertThat(authenticated()).isTrue()
- powerInteractor.setAsleepForTest()
+ fakeUserRepository.setSelectedUserInfo(
+ primaryUser,
+ SelectionStatus.SELECTION_IN_PROGRESS
+ )
assertThat(authenticated()).isFalse()
}
@Test
- fun isAuthenticatedIsResetToFalseWhenUserIsSwitching() =
+ fun isAuthenticatedIsResetToFalseWhenKeyguardDoneAnimationsFinished() =
testScope.runTest {
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
@@ -897,10 +900,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
assertThat(authenticated()).isTrue()
- fakeUserRepository.setSelectedUserInfo(
- primaryUser,
- SelectionStatus.SELECTION_IN_PROGRESS
- )
+ keyguardRepository.keyguardDoneAnimationsFinished()
assertThat(authenticated()).isFalse()
}
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/keyguard/ui/preview/KeyguardRemotePreviewManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManagerTest.kt
new file mode 100644
index 000000000000..e8504563b4ae
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManagerTest.kt
@@ -0,0 +1,40 @@
+package com.android.systemui.keyguard.ui.preview
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class KeyguardRemotePreviewManagerTest : SysuiTestCase() {
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+
+ @Test
+ fun onDestroy_clearsReferencesToRenderer() =
+ testScope.runTest {
+ val renderer = mock<KeyguardPreviewRenderer>()
+ val onDestroy: (PreviewLifecycleObserver) -> Unit = {}
+
+ val observer = PreviewLifecycleObserver(this, testDispatcher, renderer, onDestroy)
+
+ // Precondition check.
+ assertThat(observer.renderer).isNotNull()
+ assertThat(observer.onDestroy).isNotNull()
+
+ observer.onDestroy()
+
+ // The verification checks renderer/requestDestruction lambda because they-re
+ // non-singletons which can't leak KeyguardPreviewRenderer.
+ assertThat(observer.renderer).isNull()
+ assertThat(observer.onDestroy).isNull()
+ }
+}
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/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt
new file mode 100644
index 000000000000..ef2046d85a14
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt
@@ -0,0 +1,172 @@
+/*
+ * 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.smartspace
+
+import android.app.smartspace.SmartspaceManager
+import android.app.smartspace.SmartspaceSession
+import android.app.smartspace.SmartspaceTarget
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.testing.TestableLooper
+import android.view.View
+import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.smartspace.CommunalSmartspaceController
+import com.android.systemui.plugins.BcSmartspaceConfigPlugin
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.util.concurrency.Execution
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import java.util.concurrent.Executor
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+class CommunalSmartspaceControllerTest : SysuiTestCase() {
+ @Mock private lateinit var smartspaceManager: SmartspaceManager
+
+ @Mock private lateinit var execution: Execution
+
+ @Mock private lateinit var uiExecutor: Executor
+
+ @Mock private lateinit var targetFilter: SmartspaceTargetFilter
+
+ @Mock private lateinit var plugin: BcSmartspaceDataPlugin
+
+ @Mock private lateinit var precondition: SmartspacePrecondition
+
+ @Mock private lateinit var listener: BcSmartspaceDataPlugin.SmartspaceTargetListener
+
+ @Mock private lateinit var session: SmartspaceSession
+
+ private lateinit var controller: CommunalSmartspaceController
+
+ // TODO(b/272811280): Remove usage of real view
+ private val fakeParent = FrameLayout(context)
+
+ /**
+ * A class which implements SmartspaceView and extends View. This is mocked to provide the right
+ * object inheritance and interface implementation used in CommunalSmartspaceController
+ */
+ private class TestView(context: Context?) : View(context), SmartspaceView {
+ override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {}
+
+ override fun registerConfigProvider(plugin: BcSmartspaceConfigPlugin?) {}
+
+ override fun setPrimaryTextColor(color: Int) {}
+
+ override fun setUiSurface(uiSurface: String) {}
+
+ override fun setDozeAmount(amount: Float) {}
+
+ override fun setIntentStarter(intentStarter: BcSmartspaceDataPlugin.IntentStarter?) {}
+
+ override fun setFalsingManager(falsingManager: FalsingManager?) {}
+
+ override fun setDnd(image: Drawable?, description: String?) {}
+
+ override fun setNextAlarm(image: Drawable?, description: String?) {}
+
+ override fun setMediaTarget(target: SmartspaceTarget?) {}
+
+ override fun getSelectedPage(): Int {
+ return 0
+ }
+
+ override fun getCurrentCardTopPadding(): Int {
+ return 0
+ }
+ }
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ `when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(session)
+
+ controller =
+ CommunalSmartspaceController(
+ context,
+ smartspaceManager,
+ execution,
+ uiExecutor,
+ precondition,
+ Optional.of(targetFilter),
+ Optional.of(plugin)
+ )
+ }
+
+ /** Ensures smartspace session begins on a listener only flow. */
+ @Test
+ fun testConnectOnListen() {
+ `when`(precondition.conditionsMet()).thenReturn(true)
+ controller.addListener(listener)
+
+ verify(smartspaceManager).createSmartspaceSession(any())
+
+ var targetListener =
+ withArgCaptor<SmartspaceSession.OnTargetsAvailableListener> {
+ verify(session).addOnTargetsAvailableListener(any(), capture())
+ }
+
+ `when`(targetFilter.filterSmartspaceTarget(any())).thenReturn(true)
+
+ var target = Mockito.mock(SmartspaceTarget::class.java)
+ targetListener.onTargetsAvailable(listOf(target))
+
+ var targets =
+ withArgCaptor<List<SmartspaceTarget>> { verify(plugin).onTargetsAvailable(capture()) }
+
+ assertThat(targets.contains(target)).isTrue()
+
+ controller.removeListener(listener)
+
+ verify(session).close()
+ }
+
+ /**
+ * Ensures session is closed and weather plugin unregisters the notifier when weather smartspace
+ * view is detached.
+ */
+ @Test
+ fun testDisconnect_emitsEmptyListAndRemovesNotifier() {
+ `when`(precondition.conditionsMet()).thenReturn(true)
+ controller.addListener(listener)
+
+ verify(smartspaceManager).createSmartspaceSession(any())
+
+ controller.removeListener(listener)
+
+ verify(session).close()
+
+ // And the listener receives an empty list of targets and unregisters the notifier
+ verify(plugin).onTargetsAvailable(emptyList())
+ verify(plugin).registerSmartspaceEventNotifier(null)
+ }
+}
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 64c0f99f4ba7..c99cb39f91bf 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -44,6 +44,7 @@ public interface BcSmartspaceDataPlugin extends Plugin {
String UI_SURFACE_HOME_SCREEN = "home";
String UI_SURFACE_MEDIA = "media_data_manager";
String UI_SURFACE_DREAM = "dream";
+ String UI_SURFACE_GLANCEABLE_HUB = "glanceable_hub";
String ACTION = "com.android.systemui.action.PLUGIN_BC_SMARTSPACE_DATA";
int VERSION = 1;
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/drawable/arrow_pointing_down.xml b/packages/SystemUI/res/drawable/arrow_pointing_down.xml
new file mode 100644
index 000000000000..be39683cd78d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/arrow_pointing_down.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5.41,7.59L4,9l8,8 8,-8 -1.41,-1.41L12,14.17" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/record_issue_dialog.xml b/packages/SystemUI/res/layout/record_issue_dialog.xml
new file mode 100644
index 000000000000..53ad9f157a2e
--- /dev/null
+++ b/packages/SystemUI/res/layout/record_issue_dialog.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+ android:text="@string/qs_record_issue_dropdown_header" />
+
+ <Button
+ android:id="@+id/issue_type_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/qs_record_issue_dropdown_prompt"
+ android:lines="1"
+ android:drawableRight="@drawable/arrow_pointing_down"
+ android:layout_marginTop="@dimen/qqs_layout_margin_top"
+ android:focusable="false"
+ android:clickable="true" />
+
+ <!-- Screen Record Switch -->
+ <LinearLayout
+ android:id="@+id/screenrecord_switch_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/qqs_layout_margin_top"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:layout_width="@dimen/screenrecord_option_icon_size"
+ android:layout_height="@dimen/screenrecord_option_icon_size"
+ android:layout_weight="0"
+ android:src="@drawable/ic_screenrecord"
+ app:tint="?androidprv:attr/materialColorOnSurface"
+ android:layout_gravity="center"
+ android:layout_marginEnd="@dimen/screenrecord_option_padding" />
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/screenrecord_option_icon_size"
+ android:layout_weight="1"
+ android:layout_gravity="fill_vertical"
+ android:gravity="center"
+ android:text="@string/quick_settings_screen_record_label"
+ android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+ android:importantForAccessibility="no"/>
+
+ <Switch
+ android:id="@+id/screenrecord_switch"
+ android:layout_width="wrap_content"
+ android:minHeight="@dimen/screenrecord_option_icon_size"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="fill_vertical"
+ android:layout_weight="0"
+ android:contentDescription="@string/quick_settings_screen_record_label" />
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
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/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 78b701caa3b6..e10925d551e2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -831,6 +831,20 @@
<!-- QuickSettings: Text to prompt the user to stop an ongoing recording [CHAR LIMIT=20] -->
<string name="qs_record_issue_stop">Stop</string>
+ <!-- QuickSettings: Issue Type Drop down options in Record Issue Start Dialog [CHAR LIMIT=50] -->
+ <string name="qs_record_issue_dropdown_header">What part of your device experience was affected?</string>
+ <!-- QuickSettings: Issue Type Drop down prompt in Record Issue Start Dialog [CHAR LIMIT=30] -->
+ <string name="qs_record_issue_dropdown_prompt">Select issue type</string>
+ <!-- QuickSettings: Screen record switch label in Record Issue Start Dialog [CHAR LIMIT=20] -->
+ <string name="qs_record_issue_dropdown_screenrecord">Screen record</string>
+
+ <!-- QuickSettings: Issue Type Drop down choices list in Record Issue Start Dialog [CHAR LIMIT=30] -->
+ <string-array name="qs_record_issue_types">
+ <item>Performance</item>
+ <item>User Interface</item>
+ <item>Battery</item>
+ </string-array>
+
<!-- QuickSettings: Label for the toggle that controls whether One-handed mode is enabled. [CHAR LIMIT=NONE] -->
<string name="quick_settings_onehanded_label">One-handed mode</string>
@@ -1066,9 +1080,11 @@
<!-- Description for the button that opens the widget editor on click. [CHAR LIMIT=50] -->
<string name="button_to_open_widget_editor">Open the widget editor</string>
<!-- Description for the button that removes a widget on click. [CHAR LIMIT=50] -->
- <string name="button_to_remove_widget">Remove a widget</string>
+ <string name="button_to_remove_widget">Remove</string>
<!-- Text for the button that launches the hub mode widget picker. [CHAR LIMIT=50] -->
- <string name="hub_mode_add_widget_button_text">Add Widget</string>
+ <string name="hub_mode_add_widget_button_text">Add widget</string>
+ <!-- Text for the button that exits the hub mode editing mode. [CHAR LIMIT=50] -->
+ <string name="hub_mode_editing_exit_button_text">Done</string>
<!-- Related to user switcher --><skip/>
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/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
index df7182b90f12..d6a5477fd096 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
@@ -16,7 +16,6 @@
package com.android.systemui.shared.system;
-import android.annotation.IntDef;
import android.os.Build;
import android.text.TextUtils;
import android.view.View;
@@ -25,59 +24,14 @@ import com.android.internal.jank.Cuj;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
public final class InteractionJankMonitorWrapper {
- // Launcher journeys.
- public static final int CUJ_APP_LAUNCH_FROM_RECENTS = Cuj.CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS;
- public static final int CUJ_APP_LAUNCH_FROM_ICON = Cuj.CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON;
- public static final int CUJ_APP_CLOSE_TO_HOME = Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME;
- public static final int CUJ_APP_CLOSE_TO_HOME_FALLBACK =
- Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK;
- public static final int CUJ_APP_CLOSE_TO_PIP = Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_PIP;
- public static final int CUJ_QUICK_SWITCH = Cuj.CUJ_LAUNCHER_QUICK_SWITCH;
- public static final int CUJ_OPEN_ALL_APPS = Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS;
- public static final int CUJ_CLOSE_ALL_APPS_SWIPE = Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE;
- public static final int CUJ_CLOSE_ALL_APPS_TO_HOME = Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME;
- public static final int CUJ_ALL_APPS_SCROLL = Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL;
- public static final int CUJ_APP_LAUNCH_FROM_WIDGET = Cuj.CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET;
- public static final int CUJ_SPLIT_SCREEN_ENTER = Cuj.CUJ_SPLIT_SCREEN_ENTER;
- public static final int CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION =
- Cuj.CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION;
- public static final int CUJ_RECENTS_SCROLLING = Cuj.CUJ_RECENTS_SCROLLING;
- public static final int CUJ_APP_SWIPE_TO_RECENTS = Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS;
- public static final int CUJ_OPEN_SEARCH_RESULT = Cuj.CUJ_LAUNCHER_OPEN_SEARCH_RESULT;
- public static final int CUJ_LAUNCHER_UNFOLD_ANIM = Cuj.CUJ_LAUNCHER_UNFOLD_ANIM;
-
- @IntDef({
- CUJ_APP_LAUNCH_FROM_RECENTS,
- CUJ_APP_LAUNCH_FROM_ICON,
- CUJ_APP_CLOSE_TO_HOME,
- CUJ_APP_CLOSE_TO_HOME_FALLBACK,
- CUJ_APP_CLOSE_TO_PIP,
- CUJ_QUICK_SWITCH,
- CUJ_APP_LAUNCH_FROM_WIDGET,
- CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION,
- CUJ_RECENTS_SCROLLING,
- CUJ_APP_SWIPE_TO_RECENTS,
- CUJ_OPEN_ALL_APPS,
- CUJ_CLOSE_ALL_APPS_SWIPE,
- CUJ_CLOSE_ALL_APPS_TO_HOME,
- CUJ_OPEN_SEARCH_RESULT,
- CUJ_LAUNCHER_UNFOLD_ANIM,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface CujType {
- }
-
/**
* Begin a trace session.
*
* @param v an attached view.
* @param cujType the specific {@link Cuj.CujType}.
*/
- public static void begin(View v, @CujType int cujType) {
+ public static void begin(View v, @Cuj.CujType int cujType) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
InteractionJankMonitor.getInstance().begin(v, cujType);
}
@@ -89,7 +43,7 @@ public final class InteractionJankMonitorWrapper {
* @param cujType the specific {@link Cuj.CujType}.
* @param timeout duration to cancel the instrumentation in ms
*/
- public static void begin(View v, @CujType int cujType, long timeout) {
+ public static void begin(View v, @Cuj.CujType int cujType, long timeout) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
Configuration.Builder builder =
Configuration.Builder.withView(cujType, v)
@@ -104,7 +58,7 @@ public final class InteractionJankMonitorWrapper {
* @param cujType the specific {@link Cuj.CujType}.
* @param tag the tag to distinguish different flow of same type CUJ.
*/
- public static void begin(View v, @CujType int cujType, String tag) {
+ public static void begin(View v, @Cuj.CujType int cujType, String tag) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
Configuration.Builder builder =
Configuration.Builder.withView(cujType, v);
@@ -119,7 +73,7 @@ public final class InteractionJankMonitorWrapper {
*
* @param cujType the specific {@link Cuj.CujType}.
*/
- public static void end(@CujType int cujType) {
+ public static void end(@Cuj.CujType int cujType) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
InteractionJankMonitor.getInstance().end(cujType);
}
@@ -127,7 +81,7 @@ public final class InteractionJankMonitorWrapper {
/**
* Cancel the trace session.
*/
- public static void cancel(@CujType int cujType) {
+ public static void cancel(@Cuj.CujType int cujType) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
InteractionJankMonitor.getInstance().cancel(cujType);
}
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/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 1a2a4253e761..e342c6bca6fa 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -122,7 +122,7 @@ constructor(
if (!smartspaceRepository.isSmartspaceRemoteViewsEnabled) {
flowOf(emptyList())
} else {
- smartspaceRepository.lockscreenSmartspaceTargets.map { targets ->
+ smartspaceRepository.communalSmartspaceTargets.map { targets ->
targets
.filter { target ->
target.featureType == SmartspaceTarget.FEATURE_TIMER &&
diff --git a/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt
new file mode 100644
index 000000000000..c5610c877f57
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt
@@ -0,0 +1,195 @@
+/*
+ * 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.communal.smartspace
+
+import android.app.smartspace.SmartspaceConfig
+import android.app.smartspace.SmartspaceManager
+import android.app.smartspace.SmartspaceSession
+import android.app.smartspace.SmartspaceTarget
+import android.content.Context
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.UI_SURFACE_GLANCEABLE_HUB
+import com.android.systemui.smartspace.SmartspacePrecondition
+import com.android.systemui.smartspace.SmartspaceTargetFilter
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_PRECONDITION
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_TARGET_FILTER
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN
+import com.android.systemui.util.concurrency.Execution
+import java.util.Optional
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import javax.inject.Named
+
+/** Controller for managing the smartspace view on the dream */
+@SysUISingleton
+class CommunalSmartspaceController
+@Inject
+constructor(
+ private val context: Context,
+ private val smartspaceManager: SmartspaceManager?,
+ private val execution: Execution,
+ @Main private val uiExecutor: Executor,
+ @Named(DREAM_SMARTSPACE_PRECONDITION) private val precondition: SmartspacePrecondition,
+ @Named(DREAM_SMARTSPACE_TARGET_FILTER)
+ private val optionalTargetFilter: Optional<SmartspaceTargetFilter>,
+ @Named(GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN) optionalPlugin: Optional<BcSmartspaceDataPlugin>,
+) {
+ companion object {
+ private const val TAG = "CommunalSmartspaceCtrlr"
+ }
+
+ private var session: SmartspaceSession? = null
+ private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
+ private var targetFilter: SmartspaceTargetFilter? = optionalTargetFilter.orElse(null)
+
+ // A shadow copy of listeners is maintained to track whether the session should remain open.
+ private var listeners = mutableSetOf<SmartspaceTargetListener>()
+
+ private var unfilteredListeners = mutableSetOf<SmartspaceTargetListener>()
+
+ // Smartspace can be used on multiple displays, such as when the user casts their screen
+ private var smartspaceViews = mutableSetOf<SmartspaceView>()
+
+ var preconditionListener =
+ object : SmartspacePrecondition.Listener {
+ override fun onCriteriaChanged() {
+ reloadSmartspace()
+ }
+ }
+
+ init {
+ precondition.addListener(preconditionListener)
+ }
+
+ var filterListener =
+ object : SmartspaceTargetFilter.Listener {
+ override fun onCriteriaChanged() {
+ reloadSmartspace()
+ }
+ }
+
+ init {
+ targetFilter?.addListener(filterListener)
+ }
+
+ private val sessionListener =
+ SmartspaceSession.OnTargetsAvailableListener { targets ->
+ execution.assertIsMainThread()
+
+ val filteredTargets =
+ targets.filter { targetFilter?.filterSmartspaceTarget(it) ?: true }
+ plugin?.onTargetsAvailable(filteredTargets)
+ }
+
+ private fun hasActiveSessionListeners(): Boolean {
+ return smartspaceViews.isNotEmpty() ||
+ listeners.isNotEmpty() ||
+ unfilteredListeners.isNotEmpty()
+ }
+
+ private fun connectSession() {
+ if (smartspaceManager == null) {
+ return
+ }
+ if (plugin == null) {
+ return
+ }
+ if (session != null || !hasActiveSessionListeners()) {
+ return
+ }
+
+ if (!precondition.conditionsMet()) {
+ return
+ }
+
+ val newSession =
+ smartspaceManager.createSmartspaceSession(
+ SmartspaceConfig.Builder(context, UI_SURFACE_GLANCEABLE_HUB).build()
+ )
+ Log.d(TAG, "Starting smartspace session for dream")
+ newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener)
+ this.session = newSession
+
+ plugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
+
+ reloadSmartspace()
+ }
+
+ /** Disconnects the smartspace view from the smartspace service and cleans up any resources. */
+ private fun disconnect() {
+ if (hasActiveSessionListeners()) return
+
+ execution.assertIsMainThread()
+
+ if (session == null) {
+ return
+ }
+
+ session?.let {
+ it.removeOnTargetsAvailableListener(sessionListener)
+ it.close()
+ }
+
+ session = null
+
+ plugin?.registerSmartspaceEventNotifier(null)
+ plugin?.onTargetsAvailable(emptyList())
+ Log.d(TAG, "Ending smartspace session for dream")
+ }
+
+ fun addListener(listener: SmartspaceTargetListener) {
+ addAndRegisterListener(listener, plugin)
+ }
+
+ fun removeListener(listener: SmartspaceTargetListener) {
+ removeAndUnregisterListener(listener, plugin)
+ }
+
+ private fun addAndRegisterListener(
+ listener: SmartspaceTargetListener,
+ smartspaceDataPlugin: BcSmartspaceDataPlugin?
+ ) {
+ execution.assertIsMainThread()
+ smartspaceDataPlugin?.registerListener(listener)
+ listeners.add(listener)
+
+ connectSession()
+ }
+
+ private fun removeAndUnregisterListener(
+ listener: SmartspaceTargetListener,
+ smartspaceDataPlugin: BcSmartspaceDataPlugin?
+ ) {
+ execution.assertIsMainThread()
+ smartspaceDataPlugin?.unregisterListener(listener)
+ listeners.remove(listener)
+ disconnect()
+ }
+
+ private fun reloadSmartspace() {
+ session?.requestSmartspaceUpdate()
+ }
+
+ private fun onTargetsAvailableUnfiltered(targets: List<SmartspaceTarget>) {
+ unfilteredListeners.forEach { it.onSmartspaceTargetsUpdated(targets) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index 7b94fc182fe2..573a748b4290 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -76,6 +76,10 @@ constructor(
Intent(applicationContext, WidgetPickerActivity::class.java)
)
},
+ onEditDone = {
+ // TODO(b/315154364): in a separate change, lock the device and transition to GH
+ finish()
+ }
)
}
}
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/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
index 65d44957222a..3a927396527c 100644
--- a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
+++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
@@ -63,6 +63,7 @@ interface BaseComposeFacade {
activity: ComponentActivity,
viewModel: BaseCommunalViewModel,
onOpenWidgetPicker: () -> Unit,
+ onEditDone: () -> Unit,
)
/** Create a [View] to represent [viewModel] on screen. */
diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt
index 63b01edb01fa..0daa058720ba 100644
--- a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt
@@ -35,23 +35,22 @@ import java.util.concurrent.Executor
import javax.inject.Inject
/** Dialog to select contrast options */
-class ContrastDialogDelegate @Inject constructor(
- private val sysuiDialogFactory : SystemUIDialog.Factory,
+class ContrastDialogDelegate
+@Inject
+constructor(
+ private val sysuiDialogFactory: SystemUIDialog.Factory,
@Main private val mainExecutor: Executor,
private val uiModeManager: UiModeManager,
private val userTracker: UserTracker,
private val secureSettings: SecureSettings,
) : SystemUIDialog.Delegate, UiModeManager.ContrastChangeListener {
- override fun createDialog(): SystemUIDialog {
- return sysuiDialogFactory.create(this)
- }
-
@VisibleForTesting lateinit var contrastButtons: Map<Int, FrameLayout>
lateinit var dialogView: View
@VisibleForTesting var initialContrast: Float = fromContrastLevel(CONTRAST_LEVEL_STANDARD)
- override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ override fun createDialog(): SystemUIDialog {
+ val dialog = sysuiDialogFactory.create(this)
dialogView = dialog.layoutInflater.inflate(R.layout.contrast_dialog, null)
with(dialog) {
setView(dialogView)
@@ -67,12 +66,16 @@ class ContrastDialogDelegate @Inject constructor(
}
setPositiveButton(com.android.settingslib.R.string.done) { _, _ -> dialog.dismiss() }
}
+
+ return dialog
+ }
+
+ override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
contrastButtons =
mapOf(
- CONTRAST_LEVEL_STANDARD to dialogView.requireViewById(
- R.id.contrast_button_standard),
- CONTRAST_LEVEL_MEDIUM to dialogView.requireViewById(R.id.contrast_button_medium),
- CONTRAST_LEVEL_HIGH to dialogView.requireViewById(R.id.contrast_button_high)
+ CONTRAST_LEVEL_STANDARD to dialog.requireViewById(R.id.contrast_button_standard),
+ CONTRAST_LEVEL_MEDIUM to dialog.requireViewById(R.id.contrast_button_medium),
+ CONTRAST_LEVEL_HIGH to dialog.requireViewById(R.id.contrast_button_high)
)
contrastButtons.forEach { (contrastLevel, contrastButton) ->
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 b7260f2b2b94..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;
@@ -141,6 +141,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.flags.SystemPropertiesHelper;
import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
@@ -616,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();
@@ -1319,6 +1320,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters;
private SelectedUserInteractor mSelectedUserInteractor;
+ private KeyguardInteractor mKeyguardInteractor;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
@@ -1400,7 +1402,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel,
SystemPropertiesHelper systemPropertiesHelper,
Lazy<WindowManagerLockscreenVisibilityManager> wmLockscreenVisibilityManager,
- SelectedUserInteractor selectedUserInteractor) {
+ SelectedUserInteractor selectedUserInteractor,
+ KeyguardInteractor keyguardInteractor) {
mContext = context;
mUserTracker = userTracker;
mFalsingCollector = falsingCollector;
@@ -1441,6 +1444,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}));
mDozeParameters = dozeParameters;
mSelectedUserInteractor = selectedUserInteractor;
+ mKeyguardInteractor = keyguardInteractor;
mStatusBarStateController = statusBarStateController;
statusBarStateController.addCallback(this);
@@ -1498,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());
}
@@ -2618,6 +2622,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
setPendingLock(false); // user may have authenticated during the screen off animation
handleHide();
+ mKeyguardInteractor.keyguardDoneAnimationsFinished();
mUpdateMonitor.clearFingerprintRecognizedWhenKeyguardDone(currentUser);
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 331d892304b3..3925dd1620b4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -52,6 +52,7 @@ import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager;
import com.android.systemui.keyguard.data.quickaffordance.KeyguardDataQuickAffordanceModule;
import com.android.systemui.keyguard.data.repository.KeyguardFaceAuthModule;
import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl;
@@ -154,7 +155,8 @@ public class KeyguardModule {
Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel,
SystemPropertiesHelper systemPropertiesHelper,
Lazy<WindowManagerLockscreenVisibilityManager> wmLockscreenVisibilityManager,
- SelectedUserInteractor selectedUserInteractor) {
+ SelectedUserInteractor selectedUserInteractor,
+ KeyguardInteractor keyguardInteractor) {
return new KeyguardViewMediator(
context,
uiEventLogger,
@@ -199,7 +201,8 @@ public class KeyguardModule {
dreamingToLockscreenTransitionViewModel,
systemPropertiesHelper,
wmLockscreenVisibilityManager,
- selectedUserInteractor);
+ selectedUserInteractor,
+ keyguardInteractor);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index eceaf6c3c4fd..4d60dd0bea62 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -187,7 +187,8 @@ constructor(
faceManager?.sensorPropertiesInternal?.firstOrNull()?.supportsFaceDetection ?: false
private val _isAuthRunning = MutableStateFlow(false)
- override val isAuthRunning: StateFlow<Boolean> = _isAuthRunning
+ override val isAuthRunning: StateFlow<Boolean>
+ get() = _isAuthRunning
private val keyguardSessionId: InstanceId?
get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD)
@@ -253,13 +254,6 @@ constructor(
)
.andAllFlows("canFaceAuthRun", faceAuthLog)
.flowOn(backgroundDispatcher)
- .onEach {
- faceAuthLogger.canFaceAuthRunChanged(it)
- if (!it) {
- // Cancel currently running auth if any of the gating checks are false.
- cancel()
- }
- }
.stateIn(applicationScope, SharingStarted.Eagerly, false)
// Face detection can run only when lockscreen bypass is enabled
@@ -287,12 +281,9 @@ constructor(
)
.andAllFlows("canFaceDetectRun", faceDetectLog)
.flowOn(backgroundDispatcher)
- .onEach {
- if (!it) {
- cancelDetection()
- }
- }
.stateIn(applicationScope, SharingStarted.Eagerly, false)
+ observeFaceAuthGatingChecks()
+ observeFaceDetectGatingChecks()
observeFaceAuthResettingConditions()
listenForSchedulingWatchdog()
processPendingAuthRequests()
@@ -313,14 +304,14 @@ constructor(
}
private fun observeFaceAuthResettingConditions() {
- // Clear auth status when keyguard is going away or when the user is switching or device
- // starts going to sleep.
+ // Clear auth status when keyguard done animations finished or when the user is switching
+ // or device starts going to sleep.
merge(
powerInteractor.isAsleep,
if (featureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
keyguardTransitionInteractor.isInTransitionToState(KeyguardState.GONE)
} else {
- keyguardRepository.isKeyguardGoingAway
+ keyguardRepository.keyguardDoneAnimationsFinished.map { true }
},
userRepository.selectedUser.map {
it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS
@@ -347,6 +338,17 @@ constructor(
pendingAuthenticateRequest.value = null
}
+ private fun observeFaceDetectGatingChecks() {
+ canRunDetection
+ .onEach {
+ if (!it) {
+ cancelDetection()
+ }
+ }
+ .flowOn(mainDispatcher)
+ .launchIn(applicationScope)
+ }
+
private fun isUdfps() =
deviceEntryFingerprintAuthRepository.availableFpSensorType.map {
it == BiometricType.UNDER_DISPLAY_FINGERPRINT
@@ -405,6 +407,20 @@ constructor(
)
}
+ private fun observeFaceAuthGatingChecks() {
+ canRunFaceAuth
+ .onEach {
+ faceAuthLogger.canFaceAuthRunChanged(it)
+ if (!it) {
+ // Cancel currently running auth if any of the gating checks are false.
+ faceAuthLogger.cancellingFaceAuth()
+ cancel()
+ }
+ }
+ .flowOn(mainDispatcher)
+ .launchIn(applicationScope)
+ }
+
private val faceAuthCallback =
object : FaceManager.AuthenticationCallback() {
override fun onAuthenticationFailed() {
@@ -539,7 +555,7 @@ constructor(
authenticate(it.uiEvent, it.fallbackToDetection)
}
}
- .flowOn(backgroundDispatcher)
+ .flowOn(mainDispatcher)
.launchIn(applicationScope)
}
@@ -635,7 +651,6 @@ constructor(
override fun cancel() {
if (authCancellationSignal == null) return
- faceAuthLogger.cancellingFaceAuth()
authCancellationSignal?.cancel()
cancelNotReceivedHandlerJob?.cancel()
cancelNotReceivedHandlerJob =
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/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 0df7f9b809fd..31ef100abbcb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -192,6 +192,17 @@ interface KeyguardRepository {
/** Observable updated when keyguardDone should be called either now or soon. */
val keyguardDone: Flow<KeyguardDone>
+ /**
+ * Emits after the keyguard is done animating away.
+ *
+ * TODO(b/278086361): Remove once KEYGUARD_WM_STATE_REFACTOR flag is removed.
+ */
+ @Deprecated(
+ "Use KeyguardTransitionInteractor flows instead. The closest match for " +
+ "'keyguardDoneAnimationsFinished' is when the GONE transition is finished."
+ )
+ val keyguardDoneAnimationsFinished: Flow<Unit>
+
/** Receive whether clock should be centered on lockscreen. */
val clockShouldBeCentered: Flow<Boolean>
@@ -239,6 +250,17 @@ interface KeyguardRepository {
suspend fun setKeyguardDone(keyguardDoneType: KeyguardDone)
fun setClockShouldBeCentered(shouldBeCentered: Boolean)
+
+ /**
+ * Updates signal that the keyguard done animations are finished
+ *
+ * TODO(b/278086361): Remove once KEYGUARD_WM_STATE_REFACTOR flag is removed.
+ */
+ @Deprecated(
+ "Use KeyguardTransitionInteractor flows instead. The closest match for " +
+ "'keyguardDoneAnimationsFinished' is when the GONE transition is finished."
+ )
+ fun keyguardDoneAnimationsFinished()
}
/** Encapsulates application state for the keyguard. */
@@ -269,6 +291,11 @@ constructor(
_keyguardDone.emit(keyguardDoneType)
}
+ override val keyguardDoneAnimationsFinished: MutableSharedFlow<Unit> = MutableSharedFlow()
+ override fun keyguardDoneAnimationsFinished() {
+ keyguardDoneAnimationsFinished.tryEmit(Unit)
+ }
+
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
_animateBottomAreaDozingTransitions.asStateFlow()
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/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index defca18b64b8..21651ba2cc2b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -318,6 +318,10 @@ constructor(
repository.ambientIndicationVisible.value = isVisible
}
+ fun keyguardDoneAnimationsFinished() {
+ repository.keyguardDoneAnimationsFinished()
+ }
+
companion object {
private const val TAG = "KeyguardInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index fb20000471a2..e3f47397eca3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -31,7 +31,6 @@ 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.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
@@ -72,7 +71,6 @@ constructor(
private val context: Context,
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
- @Background private val backgroundDispatcher: CoroutineDispatcher,
private val repository: DeviceEntryFaceAuthRepository,
private val primaryBouncerInteractor: Lazy<PrimaryBouncerInteractor>,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
@@ -109,7 +107,6 @@ constructor(
fallbackToDetect = false
)
}
- .flowOn(backgroundDispatcher)
.launchIn(applicationScope)
alternateBouncerInteractor.isVisible
@@ -121,7 +118,6 @@ constructor(
fallbackToDetect = false
)
}
- .flowOn(backgroundDispatcher)
.launchIn(applicationScope)
merge(
@@ -150,7 +146,6 @@ constructor(
fallbackToDetect = true
)
}
- .flowOn(backgroundDispatcher)
.launchIn(applicationScope)
deviceEntryFingerprintAuthRepository.isLockedOut
@@ -163,7 +158,6 @@ constructor(
}
}
}
- .flowOn(backgroundDispatcher)
.launchIn(applicationScope)
// User switching should stop face auth and then when it is complete we should trigger face
@@ -187,7 +181,6 @@ constructor(
)
}
}
- .flowOn(backgroundDispatcher)
.launchIn(applicationScope)
}
@@ -302,7 +295,6 @@ constructor(
trustManager.clearAllBiometricRecognized(BiometricSourceType.FACE, userInfo.id)
}
}
- .flowOn(backgroundDispatcher)
.onEach { (isAuthenticated, _) ->
listeners.forEach { it.onAuthenticatedChanged(isAuthenticated) }
}
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/preview/KeyguardRemotePreviewManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
index acfd3b0bcf57..24240dfe7402 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
@@ -30,6 +30,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants
+import com.android.systemui.util.kotlin.logD
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -58,11 +59,14 @@ constructor(
observer =
PreviewLifecycleObserver(
- renderer,
applicationScope,
mainDispatcher,
+ renderer,
::destroyObserver,
)
+
+ logD(TAG) { "Created observer $observer" }
+
// Destroy any previous renderer associated with this token.
activePreviews[renderer.id]?.let { destroyObserver(it) }
activePreviews[renderer.id] = observer
@@ -80,6 +84,8 @@ constructor(
observer,
)
)
+ // NOTE: The process on the other side can retain messenger indefinitely.
+ // (e.g. GC might not trigger and cleanup the reference)
val msg = Message.obtain()
msg.replyTo = messenger
result.putParcelable(KEY_PREVIEW_CALLBACK, msg)
@@ -99,57 +105,84 @@ constructor(
}
}
- private class PreviewLifecycleObserver(
- private val renderer: KeyguardPreviewRenderer,
- private val scope: CoroutineScope,
- private val mainDispatcher: CoroutineDispatcher,
- private val requestDestruction: (PreviewLifecycleObserver) -> Unit,
- ) : Handler.Callback, IBinder.DeathRecipient {
+ companion object {
+ internal const val TAG = "KeyguardRemotePreviewManager"
+ @VisibleForTesting const val KEY_PREVIEW_SURFACE_PACKAGE = "surface_package"
+ @VisibleForTesting const val KEY_PREVIEW_CALLBACK = "callback"
+ }
+}
- private var isDestroyedOrDestroying = false
+/**
+ * Handles messages from the other process and handles cleanup.
+ *
+ * NOTE: The other process might hold on to reference of this class indefinitely. It's entirely
+ * possible that GC won't trigger and we'll leak this for all times even if [onDestroy] was called.
+ * This helps make sure no non-Singleton objects are retained beyond destruction to prevent leaks.
+ */
+@VisibleForTesting(VisibleForTesting.PRIVATE)
+class PreviewLifecycleObserver(
+ private val scope: CoroutineScope,
+ private val mainDispatcher: CoroutineDispatcher,
+ renderer: KeyguardPreviewRenderer,
+ onDestroy: (PreviewLifecycleObserver) -> Unit,
+) : Handler.Callback, IBinder.DeathRecipient {
+
+ private var isDestroyedOrDestroying = false
+ // These two are null after destruction
+ @VisibleForTesting var renderer: KeyguardPreviewRenderer?
+ @VisibleForTesting var onDestroy: ((PreviewLifecycleObserver) -> Unit)?
+
+ init {
+ this.renderer = renderer
+ this.onDestroy = onDestroy
+ }
- override fun handleMessage(message: Message): Boolean {
- if (isDestroyedOrDestroying) {
- return true
- }
+ override fun handleMessage(message: Message): Boolean {
+ if (isDestroyedOrDestroying) {
+ return true
+ }
- when (message.what) {
- KeyguardPreviewConstants.MESSAGE_ID_SLOT_SELECTED -> {
- message.data.getString(KeyguardPreviewConstants.KEY_SLOT_ID)?.let { slotId ->
- renderer.onSlotSelected(slotId = slotId)
- }
+ when (message.what) {
+ KeyguardPreviewConstants.MESSAGE_ID_SLOT_SELECTED -> {
+ message.data.getString(KeyguardPreviewConstants.KEY_SLOT_ID)?.let { slotId ->
+ checkNotNull(renderer).onSlotSelected(slotId = slotId)
}
- KeyguardPreviewConstants.MESSAGE_ID_HIDE_SMART_SPACE -> {
- renderer.hideSmartspace(
+ }
+ KeyguardPreviewConstants.MESSAGE_ID_HIDE_SMART_SPACE -> {
+ checkNotNull(renderer)
+ .hideSmartspace(
message.data.getBoolean(KeyguardPreviewConstants.KEY_HIDE_SMART_SPACE)
)
- }
- else -> requestDestruction(this)
}
-
- return true
+ else -> checkNotNull(onDestroy).invoke(this)
}
- override fun binderDied() {
- requestDestruction(this)
+ return true
+ }
+
+ override fun binderDied() {
+ onDestroy?.invoke(this)
+ }
+
+ fun onDestroy(): Pair<IBinder?, Int>? {
+ if (isDestroyedOrDestroying) {
+ return null
}
- fun onDestroy(): Pair<IBinder?, Int>? {
- if (isDestroyedOrDestroying) {
- return null
- }
+ logD(TAG) { "Destroying $this" }
- isDestroyedOrDestroying = true
- val hostToken = renderer.hostToken
+ isDestroyedOrDestroying = true
+ return renderer?.let { rendererToDestroy ->
+ this.renderer = null
+ this.onDestroy = null
+ val hostToken = rendererToDestroy.hostToken
hostToken?.unlinkToDeath(this, 0)
- scope.launch(mainDispatcher) { renderer.destroy() }
- return renderer.id
+ scope.launch(mainDispatcher) { rendererToDestroy.destroy() }
+ rendererToDestroy.id
}
}
companion object {
private const val TAG = "KeyguardRemotePreviewManager"
- @VisibleForTesting const val KEY_PREVIEW_SURFACE_PACKAGE = "surface_package"
- @VisibleForTesting const val KEY_PREVIEW_CALLBACK = "callback"
}
}
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/media/controls/ui/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
index 14d4b6800b0a..c87fd14a943d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
@@ -119,7 +119,7 @@ internal constructor(
::AnimatingColorTransition
)
- val bgColor = context.getColor(com.google.android.material.R.color.material_dynamic_secondary95)
+ val bgColor = context.getColor(com.google.android.material.R.color.material_dynamic_neutral20)
val surfaceColor =
animatingColorTransitionFactory(bgColor, ::surfaceFromScheme) { surfaceColor ->
val colorList = ColorStateList.valueOf(surfaceColor)
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 a4088f81f062..66da8bdd0311 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles
+import android.app.AlertDialog
import android.content.Intent
import android.os.Handler
import android.os.Looper
@@ -24,8 +25,11 @@ import android.text.TextUtils
import android.view.View
import android.widget.Switch
import androidx.annotation.VisibleForTesting
+import com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN
import com.android.internal.logging.MetricsLogger
import com.android.systemui.Flags.recordIssueQsTile
+import com.android.systemui.animation.DialogCuj
+import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
@@ -36,7 +40,12 @@ import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
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
import javax.inject.Inject
class RecordIssueTile
@@ -50,7 +59,12 @@ constructor(
metricsLogger: MetricsLogger,
statusBarStateController: StatusBarStateController,
activityStarter: ActivityStarter,
- qsLogger: QSLogger
+ qsLogger: QSLogger,
+ private val keyguardDismissUtil: KeyguardDismissUtil,
+ private val keyguardStateController: KeyguardStateController,
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val sysuiDialogFactory: SystemUIDialog.Factory,
+ private val userContextProvider: UserContextProvider,
) :
QSTileImpl<QSTile.BooleanState>(
host,
@@ -76,11 +90,41 @@ constructor(
handlesLongClick = false
}
- override fun handleClick(view: View?) {
- isRecording = !isRecording
+ @VisibleForTesting
+ public override fun handleClick(view: View?) {
+ if (isRecording) {
+ isRecording = false
+ } else {
+ mUiHandler.post { showPrompt(view) }
+ }
refreshState()
}
+ private fun showPrompt(view: View?) {
+ val dialog: AlertDialog =
+ RecordIssueDialogDelegate(sysuiDialogFactory, userContextProvider) {
+ isRecording = true
+ refreshState()
+ }
+ .createDialog()
+ val dismissAction =
+ ActivityStarter.OnDismissAction {
+ // We animate from the touched view only if we are not on the keyguard, given
+ // that if we are we will dismiss it which will also collapse the shade.
+ if (view != null && !keyguardStateController.isShowing) {
+ dialogLaunchAnimator.showFromView(
+ dialog,
+ view,
+ DialogCuj(CUJ_SHADE_DIALOG_OPEN, TILE_SPEC)
+ )
+ } else {
+ dialog.show()
+ }
+ false
+ }
+ keyguardDismissUtil.executeWhenUnlocked(dismissAction, false, true)
+ }
+
override fun getLongClickIntent(): Intent? = null
@VisibleForTesting
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
new file mode 100644
index 000000000000..5bf44fa5b143
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -0,0 +1,113 @@
+/*
+ * 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.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
+import android.os.Bundle
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.WindowManager
+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 {
+
+ @SuppressLint("UseSwitchCompatOrMaterialCode") private lateinit var screenRecordSwitch: Switch
+ private lateinit var issueTypeButton: Button
+
+ override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ dialog.apply {
+ setView(LayoutInflater.from(context).inflate(R.layout.record_issue_dialog, null))
+ setTitle(context.getString(R.string.qs_record_issue_label))
+ setIcon(R.drawable.qs_record_issue_icon_off)
+ setNegativeButton(R.string.cancel) { _, _ -> dismiss() }
+ setPositiveButton(R.string.qs_record_issue_start) { _, _ ->
+ onStarted.run()
+ if (screenRecordSwitch.isChecked) {
+ requestScreenCapture()
+ }
+ dismiss()
+ }
+ }
+ }
+
+ override fun createDialog(): SystemUIDialog = factory.create(this)
+
+ override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ dialog.apply {
+ window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
+ window?.setGravity(Gravity.CENTER)
+
+ screenRecordSwitch = requireViewById(R.id.screenrecord_switch)
+ issueTypeButton = requireViewById(R.id.issue_type_button)
+ issueTypeButton.setOnClickListener { onIssueTypeClicked(context) }
+ }
+ }
+
+ private fun onIssueTypeClicked(context: Context) {
+ val selectedCategory = issueTypeButton.text.toString()
+ val popupMenu = PopupMenu(context, issueTypeButton)
+
+ context.resources.getStringArray(R.array.qs_record_issue_types).forEachIndexed { i, cat ->
+ popupMenu.menu.add(0, 0, i, cat).apply {
+ setIcon(R.drawable.arrow_pointing_down)
+ if (selectedCategory != cat) {
+ iconTintList = ColorStateList.valueOf(Color.TRANSPARENT)
+ }
+ }
+ }
+ popupMenu.apply {
+ setOnMenuItemClickListener {
+ issueTypeButton.text = it.title
+ true
+ }
+ setForceShowIcon(true)
+ 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/smartspace/dagger/SmartspaceModule.kt b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
index c59ef2632f15..d26fded19cc1 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
@@ -59,6 +59,11 @@ abstract class SmartspaceModule {
* The BcSmartspaceDataPlugin for the standalone weather.
*/
const val WEATHER_SMARTSPACE_DATA_PLUGIN = "weather_smartspace_data_plugin"
+
+ /**
+ * The BcSmartspaceDataProvider for the glanceable hub.
+ */
+ const val GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN = "glanceable_hub_smartspace_data_plugin"
}
@BindsOptionalOf
@@ -78,4 +83,8 @@ abstract class SmartspaceModule {
abstract fun bindSmartspacePrecondition(
lockscreenPrecondition: LockscreenPrecondition?
): SmartspacePrecondition?
+
+ @BindsOptionalOf
+ @Named(GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN)
+ abstract fun optionalBcSmartspaceDataPlugin(): BcSmartspaceDataPlugin?
}
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt b/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt
index 2fc0ec290a90..095d30ef55df 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt
@@ -19,9 +19,9 @@ package com.android.systemui.smartspace.data.repository
import android.app.smartspace.SmartspaceTarget
import android.os.Parcelable
import android.widget.RemoteViews
+import com.android.systemui.communal.smartspace.CommunalSmartspaceController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.BcSmartspaceDataPlugin
-import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -32,37 +32,37 @@ interface SmartspaceRepository {
/** Whether [RemoteViews] are passed through smartspace targets. */
val isSmartspaceRemoteViewsEnabled: Boolean
- /** Smartspace targets for the lockscreen surface. */
- val lockscreenSmartspaceTargets: Flow<List<SmartspaceTarget>>
+ /** Smartspace targets for the communal surface. */
+ val communalSmartspaceTargets: Flow<List<SmartspaceTarget>>
}
@SysUISingleton
class SmartspaceRepositoryImpl
@Inject
constructor(
- private val lockscreenSmartspaceController: LockscreenSmartspaceController,
+ private val communalSmartspaceController: CommunalSmartspaceController,
) : SmartspaceRepository, BcSmartspaceDataPlugin.SmartspaceTargetListener {
override val isSmartspaceRemoteViewsEnabled: Boolean
get() = android.app.smartspace.flags.Flags.remoteViews()
- private val _lockscreenSmartspaceTargets: MutableStateFlow<List<SmartspaceTarget>> =
+ private val _communalSmartspaceTargets: MutableStateFlow<List<SmartspaceTarget>> =
MutableStateFlow(emptyList())
- override val lockscreenSmartspaceTargets: Flow<List<SmartspaceTarget>> =
- _lockscreenSmartspaceTargets
+ override val communalSmartspaceTargets: Flow<List<SmartspaceTarget>> =
+ _communalSmartspaceTargets
.onStart {
- lockscreenSmartspaceController.addListener(listener = this@SmartspaceRepositoryImpl)
+ communalSmartspaceController.addListener(listener = this@SmartspaceRepositoryImpl)
}
.onCompletion {
- lockscreenSmartspaceController.removeListener(
+ communalSmartspaceController.removeListener(
listener = this@SmartspaceRepositoryImpl
)
}
override fun onSmartspaceTargetsUpdated(targetsNullable: MutableList<out Parcelable>?) {
targetsNullable?.let { targets ->
- _lockscreenSmartspaceTargets.value = targets.filterIsInstance<SmartspaceTarget>()
+ _communalSmartspaceTargets.value = targets.filterIsInstance<SmartspaceTarget>()
}
- ?: run { _lockscreenSmartspaceTargets.value = emptyList() }
+ ?: run { _communalSmartspaceTargets.value = emptyList() }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
index 92391e7c76f0..e1e30e1d74f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -17,7 +17,9 @@ package com.android.systemui.statusbar.notification.icon.ui.viewbinder
import android.graphics.Color
import android.graphics.Rect
+import android.util.Log
import android.view.View
+import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.annotation.ColorInt
import androidx.collection.ArrayMap
@@ -220,7 +222,7 @@ object NotificationIconContainerViewBinder {
notifyBindingFailures: (Collection<String>) -> Unit,
viewStore: IconViewStore,
bindIcon: suspend (iconKey: String, view: StatusBarIconView) -> Unit = { _, _ -> },
- ): Unit = coroutineScope {
+ ) {
val iconSizeFlow: Flow<Int> =
configuration.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size_sp,
@@ -235,6 +237,21 @@ object NotificationIconContainerViewBinder {
->
FrameLayout.LayoutParams(iconSize + 2 * iconHPadding, statusBarHeight)
}
+ try {
+ bindIcons(view, layoutParams, notifyBindingFailures, viewStore, bindIcon)
+ } finally {
+ // Detach everything so that child SBIVs don't hold onto a reference to the container.
+ view.detachAllIcons()
+ }
+ }
+
+ private suspend fun Flow<NotificationIconsViewData>.bindIcons(
+ view: NotificationIconContainer,
+ layoutParams: Flow<FrameLayout.LayoutParams>,
+ notifyBindingFailures: (Collection<String>) -> Unit,
+ viewStore: IconViewStore,
+ bindIcon: suspend (iconKey: String, view: StatusBarIconView) -> Unit,
+ ): Unit = coroutineScope {
val failedBindings = mutableSetOf<String>()
val boundViewsByNotifKey = ArrayMap<String, Pair<StatusBarIconView, Job>>()
var prevIcons = NotificationIconsViewData()
@@ -266,9 +283,17 @@ object NotificationIconContainerViewBinder {
continue
}
failedBindings.remove(notifKey)
- // The view might still be transiently added if it was just removed and added
- // again
- view.removeTransientView(sbiv)
+ (sbiv.parent as? ViewGroup)?.run {
+ if (this !== view) {
+ Log.wtf(TAG, "StatusBarIconView($notifKey) has an unexpected parent")
+ }
+ // If the container was re-inflated and re-bound, then SBIVs might still be
+ // attached to the prior view.
+ removeView(sbiv)
+ // The view might still be transiently added if it was just removed and
+ // added again.
+ removeTransientView(sbiv)
+ }
view.addView(sbiv, idx)
boundViewsByNotifKey.remove(notifKey)?.second?.cancel()
boundViewsByNotifKey[notifKey] =
@@ -351,7 +376,8 @@ object NotificationIconContainerViewBinder {
fun iconView(key: String): StatusBarIconView?
}
- @ColorInt private val DEFAULT_AOD_ICON_COLOR = Color.WHITE
+ @ColorInt private const val DEFAULT_AOD_ICON_COLOR = Color.WHITE
+ private const val TAG = "NotifIconContainerViewBinder"
}
/** [IconViewStore] for the [com.android.systemui.statusbar.NotificationShelf] */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 00e78a49ba19..0dabafbdecb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -400,6 +400,21 @@ public class NotificationIconContainer extends ViewGroup {
}
}
+ /**
+ * Removes all child {@link StatusBarIconView} instances from this container, immediately and
+ * without animation. This should be called when tearing down this container so that external
+ * icon views are not holding onto a reference thru {@link View#getParent()}.
+ */
+ public void detachAllIcons() {
+ boolean animsWereEnabled = mAnimationsEnabled;
+ boolean wasChangingPositions = mChangingViewPositions;
+ mAnimationsEnabled = false;
+ mChangingViewPositions = true;
+ removeAllViews();
+ mChangingViewPositions = wasChangingPositions;
+ mAnimationsEnabled = animsWereEnabled;
+ }
+
public boolean areIconsOverflowing() {
return mIsShowingOverflowDot;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 756c440eca89..0c5472f0ecfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -41,6 +41,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.log.core.LogLevel;
import com.android.systemui.res.R;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
@@ -49,6 +50,7 @@ import dagger.Lazy;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
+import java.util.function.Consumer;
import javax.inject.Inject;
@@ -210,23 +212,33 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
private void notifyKeyguardChanged() {
Trace.beginSection("KeyguardStateController#notifyKeyguardChanged");
// Copy the list to allow removal during callback.
- new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
+ invokeForEachCallback(Callback::onKeyguardShowingChanged);
Trace.endSection();
}
private void notifyKeyguardFaceAuthEnabledChanged() {
+ invokeForEachCallback(Callback::onFaceEnrolledChanged);
+ }
+
+ private void invokeForEachCallback(Consumer<Callback> consumer) {
// Copy the list to allow removal during callback.
- new ArrayList<>(mCallbacks).forEach(callback -> {
+ ArrayList<Callback> copyOfCallbacks = new ArrayList<>(mCallbacks);
+ for (int i = 0; i < copyOfCallbacks.size(); i++) {
+ Callback callback = copyOfCallbacks.get(i);
+ // Temporary fix for b/315731775, callback is null even though only non-null callbacks
+ // are added to the list by addCallback
if (callback != null) {
- callback.onFaceEnrolledChanged();
+ consumer.accept(callback);
+ } else {
+ mLogger.log("KeyguardStateController callback is null", LogLevel.DEBUG);
}
- });
+ }
}
private void notifyUnlockedChanged() {
Trace.beginSection("KeyguardStateController#notifyUnlockedChanged");
// Copy the list to allow removal during callback.
- new ArrayList<>(mCallbacks).forEach(Callback::onUnlockedChanged);
+ invokeForEachCallback(Callback::onUnlockedChanged);
Trace.endSection();
}
@@ -242,10 +254,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardFadingAway",
keyguardFadingAway ? 1 : 0);
mKeyguardFadingAway = keyguardFadingAway;
- ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
- for (int i = 0; i < callbacks.size(); i++) {
- callbacks.get(i).onKeyguardFadingAwayChanged();
- }
+ invokeForEachCallback(Callback::onKeyguardFadingAwayChanged);
}
}
@@ -359,7 +368,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardGoingAway",
keyguardGoingAway ? 1 : 0);
mKeyguardGoingAway = keyguardGoingAway;
- new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardGoingAwayChanged);
+ invokeForEachCallback(Callback::onKeyguardGoingAwayChanged);
}
}
@@ -368,7 +377,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
if (mPrimaryBouncerShowing != showing) {
mPrimaryBouncerShowing = showing;
- new ArrayList<>(mCallbacks).forEach(Callback::onPrimaryBouncerShowingChanged);
+ invokeForEachCallback(Callback::onPrimaryBouncerShowingChanged);
}
}
@@ -392,13 +401,13 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
boolean dismissingFromTouch) {
mDismissAmount = dismissAmount;
mDismissingFromTouch = dismissingFromTouch;
- new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardDismissAmountChanged);
+ invokeForEachCallback(Callback::onKeyguardDismissAmountChanged);
}
@Override
public void setLaunchTransitionFadingAway(boolean fadingAway) {
mLaunchTransitionFadingAway = fadingAway;
- new ArrayList<>(mCallbacks).forEach(Callback::onLaunchTransitionFadingAwayChanged);
+ invokeForEachCallback(Callback::onLaunchTransitionFadingAwayChanged);
}
@Override
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/src/com/android/systemui/util/kotlin/Log.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Log.kt
new file mode 100644
index 000000000000..2f6c450e924c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Log.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import android.util.Log
+
+/** Logs message at [Log.DEBUG] level. Won't call the lambda if [DEBUG] is not loggable. */
+inline fun logD(tag: String, messageLambda: () -> String) {
+ if (Log.isLoggable(tag, Log.DEBUG)) {
+ Log.d(tag, messageLambda.invoke())
+ }
+}
+
+/** Logs message at [Log.VERBOSE] level. Won't call the lambda if [VERBOSE] is not loggable. */
+inline fun logV(tag: String, messageLambda: () -> String) {
+ if (Log.isLoggable(tag, Log.VERBOSE)) {
+ Log.v(tag, messageLambda.invoke())
+ }
+}
+
+/** Logs message at [Log.INFO] level. Won't call the lambda if [INFO] is not loggable. */
+inline fun logI(tag: String, messageLambda: () -> String) {
+ if (Log.isLoggable(tag, Log.INFO)) {
+ Log.i(tag, messageLambda.invoke())
+ }
+}
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/contrast/ContrastDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt
index e931384fd61e..65f68f9df3e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt
@@ -22,6 +22,7 @@ import android.provider.Settings
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.LayoutInflater
+import android.view.View
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -39,6 +40,8 @@ import com.android.systemui.util.time.FakeSystemClock
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.eq
import org.mockito.Mockito.verify
@@ -73,13 +76,20 @@ class ContrastDialogDelegateTest : SysuiTestCase() {
if (Looper.myLooper() == null) Looper.prepare()
mContrastDialogDelegate =
- ContrastDialogDelegate(
- sysuiDialogFactory,
- mainExecutor,
- mockUiModeManager,
- mockUserTracker,
- mockSecureSettings
- )
+ ContrastDialogDelegate(
+ sysuiDialogFactory,
+ mainExecutor,
+ mockUiModeManager,
+ mockUserTracker,
+ mockSecureSettings
+ )
+
+ mContrastDialogDelegate.createDialog()
+ val viewCaptor = ArgumentCaptor.forClass(View::class.java)
+ verify(sysuiDialog).setView(viewCaptor.capture())
+ whenever(sysuiDialog.requireViewById(anyInt()) as View?).then {
+ viewCaptor.value.requireViewById(it.getArgument(0))
+ }
}
@Test
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 ae5f625b1c8d..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;
@@ -93,6 +94,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.flags.SystemPropertiesHelper;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -190,6 +192,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock ShadeInteractor mShadeInteractor;
private @Mock ShadeWindowLogger mShadeWindowLogger;
private @Mock SelectedUserInteractor mSelectedUserInteractor;
+ private @Mock KeyguardInteractor mKeyguardInteractor;
private @Captor ArgumentCaptor<KeyguardStateController.Callback>
mKeyguardStateControllerCallback;
private @Captor ArgumentCaptor<KeyguardUpdateMonitorCallback>
@@ -264,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);
@@ -1131,7 +1134,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
() -> mDreamingToLockscreenTransitionViewModel,
mSystemPropertiesHelper,
() -> mock(WindowManagerLockscreenVisibilityManager.class),
- mSelectedUserInteractor);
+ mSelectedUserInteractor,
+ mKeyguardInteractor);
mViewMediator.start();
mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
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/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 4ab8e28bc232..6eb95bddaf53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -137,7 +137,6 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
mContext,
testScope.backgroundScope,
dispatcher,
- dispatcher,
faceAuthRepository,
{
PrimaryBouncerInteractor(
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 d8199c527cac..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
@@ -23,6 +23,7 @@ import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -30,12 +31,20 @@ 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
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.isA
import org.mockito.Mock
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
/**
@@ -53,15 +62,23 @@ class RecordIssueTileTest : SysuiTestCase() {
@Mock private lateinit var statusBarStateController: StatusBarStateController
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var qsLogger: QSLogger
-
+ @Mock private lateinit var keyguardDismissUtil: KeyguardDismissUtil
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @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
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
whenever(host.context).thenReturn(mContext)
+ whenever(dialogFactory.create(any())).thenReturn(dialog)
- val testableLooper = TestableLooper.get(this)
+ testableLooper = TestableLooper.get(this)
tile =
RecordIssueTile(
host,
@@ -72,7 +89,12 @@ class RecordIssueTileTest : SysuiTestCase() {
metricsLogger,
statusBarStateController,
activityStarter,
- qsLogger
+ qsLogger,
+ keyguardDismissUtil,
+ keyguardStateController,
+ dialogLauncherAnimator,
+ dialogFactory,
+ userContextProvider,
)
}
@@ -119,4 +141,18 @@ class RecordIssueTileTest : SysuiTestCase() {
assertThat(testState.state).isEqualTo(Tile.STATE_ACTIVE)
}
+
+ @Test
+ fun showPrompt_shouldUseKeyguardDismissUtil_ToShowDialog() {
+ tile.isRecording = false
+ tile.handleClick(null)
+ testableLooper.processAllMessages()
+
+ verify(keyguardDismissUtil)
+ .executeWhenUnlocked(
+ isA(ActivityStarter.OnDismissAction::class.java),
+ eq(false),
+ eq(true)
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
new file mode 100644
index 000000000000..c5d35245ba7c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
@@ -0,0 +1,94 @@
+/*
+ * 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.recordissue
+
+import android.app.Dialog
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.widget.Button
+import android.widget.Switch
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.model.SysUiState
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class RecordIssueDialogDelegateTest : SysuiTestCase() {
+
+ private lateinit var dialog: SystemUIDialog
+ private lateinit var latch: CountDownLatch
+
+ @Before
+ fun setup() {
+ val dialogFactory =
+ SystemUIDialog.Factory(
+ context,
+ mock<FeatureFlags>(),
+ mock<SystemUIDialogManager>(),
+ mock<SysUiState>().apply {
+ whenever(setFlag(anyInt(), anyBoolean())).thenReturn(this)
+ },
+ mock<BroadcastDispatcher>(),
+ mock<DialogLaunchAnimator>()
+ )
+
+ latch = CountDownLatch(1)
+ dialog =
+ RecordIssueDialogDelegate(dialogFactory, mock()) { latch.countDown() }.createDialog()
+ dialog.show()
+ }
+
+ @After
+ fun teardown() {
+ dialog.dismiss()
+ }
+
+ @Test
+ fun dialog_hasCorrectUiElements_afterCreation() {
+ dialog.requireViewById<Switch>(R.id.screenrecord_switch)
+ dialog.requireViewById<Button>(R.id.issue_type_button)
+
+ assertThat(dialog.getButton(Dialog.BUTTON_POSITIVE).text)
+ .isEqualTo(context.getString(R.string.qs_record_issue_start))
+ assertThat(dialog.getButton(Dialog.BUTTON_NEGATIVE).text)
+ .isEqualTo(context.getString(R.string.cancel))
+ }
+
+ @Test
+ fun onStarted_isCalled_afterStartButtonIsClicked() {
+ dialog.getButton(Dialog.BUTTON_POSITIVE).callOnClick()
+ latch.await(1L, TimeUnit.MILLISECONDS)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
index 0f33aaf20195..2c7b60660165 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
@@ -56,6 +56,7 @@ import com.google.common.util.concurrent.Futures;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -138,6 +139,7 @@ public final class AppClipsActivityTest extends SysuiTestCase {
}
@Test
+ @Ignore("b/315848285")
public void screenshotDisplayed_userConsented_screenshotExportedSuccessfully() {
ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> {
assertThat(resultCode).isEqualTo(RESULT_OK);
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/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index c5d745a65e96..4200f05ad64b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -41,6 +41,10 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository {
private val _deferKeyguardDone: MutableSharedFlow<KeyguardDone> = MutableSharedFlow()
override val keyguardDone: Flow<KeyguardDone> = _deferKeyguardDone
+ private val _keyguardDoneAnimationsFinished: MutableSharedFlow<Unit> =
+ MutableSharedFlow(extraBufferCapacity = 1)
+ override val keyguardDoneAnimationsFinished: Flow<Unit> = _keyguardDoneAnimationsFinished
+
private val _clockShouldBeCentered = MutableStateFlow<Boolean>(true)
override val clockShouldBeCentered: Flow<Boolean> = _clockShouldBeCentered
@@ -176,6 +180,10 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository {
_deferKeyguardDone.emit(timing)
}
+ override fun keyguardDoneAnimationsFinished() {
+ _keyguardDoneAnimationsFinished.tryEmit(Unit)
+ }
+
override fun setClockShouldBeCentered(shouldBeCentered: Boolean) {
_clockShouldBeCentered.value = shouldBeCentered
}
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/smartspace/data/repository/FakeSmartspaceRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt
index c8013ef96fa7..862e52d7703f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt
@@ -10,12 +10,12 @@ class FakeSmartspaceRepository(
override val isSmartspaceRemoteViewsEnabled = smartspaceRemoteViewsEnabled
- private val _lockscreenSmartspaceTargets: MutableStateFlow<List<SmartspaceTarget>> =
+ private val _communalSmartspaceTargets: MutableStateFlow<List<SmartspaceTarget>> =
MutableStateFlow(emptyList())
- override val lockscreenSmartspaceTargets: Flow<List<SmartspaceTarget>> =
- _lockscreenSmartspaceTargets
+ override val communalSmartspaceTargets: Flow<List<SmartspaceTarget>> =
+ _communalSmartspaceTargets
- fun setLockscreenSmartspaceTargets(targets: List<SmartspaceTarget>) {
- _lockscreenSmartspaceTargets.value = targets
+ fun setCommunalSmartspaceTargets(targets: List<SmartspaceTarget>) {
+ _communalSmartspaceTargets.value = targets
}
}
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/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index b315f4a0f0c5..7fcef9c90812 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -76,6 +76,7 @@ import android.util.Size;
import android.view.Surface;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.camera.extensions.impl.AutoImageCaptureExtenderImpl;
import androidx.camera.extensions.impl.AutoPreviewExtenderImpl;
import androidx.camera.extensions.impl.BeautyImageCaptureExtenderImpl;
@@ -94,6 +95,7 @@ import androidx.camera.extensions.impl.PreviewExtenderImpl;
import androidx.camera.extensions.impl.PreviewExtenderImpl.ProcessorType;
import androidx.camera.extensions.impl.PreviewImageProcessorImpl;
import androidx.camera.extensions.impl.ProcessResultImpl;
+import androidx.camera.extensions.impl.ProcessorImpl;
import androidx.camera.extensions.impl.RequestUpdateProcessorImpl;
import androidx.camera.extensions.impl.advanced.AdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.AutoAdvancedExtenderImpl;
@@ -101,6 +103,7 @@ import androidx.camera.extensions.impl.advanced.BeautyAdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.BokehAdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.Camera2OutputConfigImpl;
import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImpl;
+import androidx.camera.extensions.impl.advanced.EyesFreeVideographyAdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.HdrAdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.ImageProcessorImpl;
import androidx.camera.extensions.impl.advanced.ImageReaderOutputConfigImpl;
@@ -112,6 +115,8 @@ import androidx.camera.extensions.impl.advanced.RequestProcessorImpl;
import androidx.camera.extensions.impl.advanced.SessionProcessorImpl;
import androidx.camera.extensions.impl.advanced.SurfaceOutputConfigImpl;
+import com.android.internal.camera.flags.Flags;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -135,22 +140,28 @@ public class CameraExtensionsProxyService extends Service {
private static final String RESULTS_VERSION_PREFIX = "1.3";
// Support for various latency improvements
private static final String LATENCY_VERSION_PREFIX = "1.4";
- private static final String[] ADVANCED_VERSION_PREFIXES = {LATENCY_VERSION_PREFIX,
- ADVANCED_VERSION_PREFIX, RESULTS_VERSION_PREFIX };
- private static final String[] SUPPORTED_VERSION_PREFIXES = {LATENCY_VERSION_PREFIX,
- RESULTS_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, "1.1", NON_INIT_VERSION_PREFIX};
+ private static final String EFV_VERSION_PREFIX = "1.5";
+ private static final String[] ADVANCED_VERSION_PREFIXES = {EFV_VERSION_PREFIX,
+ LATENCY_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, RESULTS_VERSION_PREFIX };
+ private static final String[] SUPPORTED_VERSION_PREFIXES = {EFV_VERSION_PREFIX,
+ LATENCY_VERSION_PREFIX, RESULTS_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, "1.1",
+ NON_INIT_VERSION_PREFIX};
private static final boolean EXTENSIONS_PRESENT = checkForExtensions();
private static final String EXTENSIONS_VERSION = EXTENSIONS_PRESENT ?
(new ExtensionVersionImpl()).checkApiVersion(LATEST_VERSION) : null;
private static final boolean ESTIMATED_LATENCY_API_SUPPORTED = checkForLatencyAPI();
private static final boolean LATENCY_IMPROVEMENTS_SUPPORTED = EXTENSIONS_PRESENT &&
- (EXTENSIONS_VERSION.startsWith(LATENCY_VERSION_PREFIX));
+ (EXTENSIONS_VERSION.startsWith(LATENCY_VERSION_PREFIX) ||
+ (EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX)));
+ private static final boolean EFV_SUPPORTED = EXTENSIONS_PRESENT &&
+ (EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX));
private static final boolean ADVANCED_API_SUPPORTED = checkForAdvancedAPI();
private static final boolean INIT_API_SUPPORTED = EXTENSIONS_PRESENT &&
(!EXTENSIONS_VERSION.startsWith(NON_INIT_VERSION_PREFIX));
private static final boolean RESULT_API_SUPPORTED = EXTENSIONS_PRESENT &&
(EXTENSIONS_VERSION.startsWith(RESULTS_VERSION_PREFIX) ||
- EXTENSIONS_VERSION.startsWith(LATENCY_VERSION_PREFIX));
+ EXTENSIONS_VERSION.startsWith(LATENCY_VERSION_PREFIX) ||
+ EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX));
private HashMap<String, Long> mMetadataVendorIdMap = new HashMap<>();
private CameraManager mCameraManager;
@@ -509,6 +520,167 @@ public class CameraExtensionsProxyService extends Service {
*/
public static Pair<PreviewExtenderImpl, ImageCaptureExtenderImpl> initializeExtension(
int extensionType) {
+ if (Flags.concertMode()) {
+ if (extensionType == CameraExtensionCharacteristics.EXTENSION_EYES_FREE_VIDEOGRAPHY) {
+ // Basic extensions are deprecated starting with extension version 1.5
+ return new Pair<>(new PreviewExtenderImpl() {
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ return false;
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+
+ }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl getCaptureStage() {
+ return null;
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ return null;
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) { }
+
+ @Override
+ public void onDeInit() { }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onPresetSession() {
+ return null;
+ }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onEnableSession() {
+ return null;
+ }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onDisableSession() {
+ return null;
+ }
+
+ @Override
+ public int onSessionType() {
+ return 0;
+ }
+ }, new ImageCaptureExtenderImpl() {
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ return false;
+ }
+
+ @Override
+ public void init(String cameraId,
+ CameraCharacteristics cameraCharacteristics) { }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ return null;
+ }
+
+ @Override
+ public
+ List<androidx.camera.extensions.impl.CaptureStageImpl> getCaptureStages() {
+ return null;
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ return 0;
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(
+ Size captureSize) {
+ return null;
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(
+ Size captureOutputSize) {
+ return null;
+ }
+
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ return null;
+ }
+
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ return null;
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return false;
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ return null;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return false;
+ }
+
+ @Override
+ public void onInit(String cameraId,
+ CameraCharacteristics cameraCharacteristics, Context context) { }
+
+ @Override
+ public void onDeInit() { }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onPresetSession() {
+ return null;
+ }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onEnableSession() {
+ return null;
+ }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onDisableSession() {
+ return null;
+ }
+
+ @Override
+ public int onSessionType() {
+ return 0;
+ }
+ });
+ }
+ }
+
switch (extensionType) {
case CameraExtensionCharacteristics.EXTENSION_AUTOMATIC:
return new Pair<>(new AutoPreviewExtenderImpl(),
@@ -533,6 +705,82 @@ public class CameraExtensionsProxyService extends Service {
* @hide
*/
public static AdvancedExtenderImpl initializeAdvancedExtensionImpl(int extensionType) {
+ if (Flags.concertMode()) {
+ if (extensionType == CameraExtensionCharacteristics.EXTENSION_EYES_FREE_VIDEOGRAPHY) {
+ if (EFV_SUPPORTED) {
+ return new EyesFreeVideographyAdvancedExtenderImpl();
+ } else {
+ return new AdvancedExtenderImpl() {
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ return false;
+ }
+
+ @Override
+ public void init(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(String cameraId,
+ Size captureOutputSize, int imageFormat) {
+ return null;
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
+ String cameraId) {
+ return null;
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
+ String cameraId) {
+ return null;
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPostviewResolutions(
+ Size captureSize) {
+ return null;
+ }
+
+ @Override
+ public List<Size> getSupportedYuvAnalysisResolutions(String cameraId) {
+ return null;
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ return null;
+ }
+
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ return null;
+ }
+
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ return null;
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return false;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return false;
+ }
+ };
+ }
+ }
+ }
+
switch (extensionType) {
case CameraExtensionCharacteristics.EXTENSION_AUTOMATIC:
return new AutoAdvancedExtenderImpl();
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index d175713eb92f..513c09587026 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -16,6 +16,8 @@
package android.platform.test.ravenwood;
+import static org.junit.Assert.fail;
+
import android.platform.test.annotations.IgnoreUnderRavenwood;
import org.junit.Assume;
@@ -36,6 +38,15 @@ public class RavenwoodRule implements TestRule {
private static final boolean IS_UNDER_RAVENWOOD = RavenwoodRuleImpl.isUnderRavenwood();
+ /**
+ * When probing is enabled, all tests will be unconditionally run under Ravenwood to detect
+ * cases where a test is able to pass despite being marked as {@code IgnoreUnderRavenwood}.
+ *
+ * This is typically helpful for internal maintainers discovering tests that had previously
+ * been ignored, but now have enough Ravenwood-supported functionality to be enabled.
+ */
+ private static final boolean ENABLE_PROBE_IGNORED = false; // DO NOT SUBMIT WITH TRUE
+
private static final int SYSTEM_UID = 1000;
private static final int NOBODY_UID = 9999;
private static final int FIRST_APPLICATION_UID = 10000;
@@ -97,26 +108,76 @@ public class RavenwoodRule implements TestRule {
return IS_UNDER_RAVENWOOD;
}
+ /**
+ * Test if the given {@link Description} has been marked with an {@link IgnoreUnderRavenwood}
+ * annotation, either at the method or class level.
+ */
+ private static boolean hasIgnoreUnderRavenwoodAnnotation(Description description) {
+ if (description.getTestClass().getAnnotation(IgnoreUnderRavenwood.class) != null) {
+ return true;
+ } else if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
@Override
public Statement apply(Statement base, Description description) {
+ if (ENABLE_PROBE_IGNORED) {
+ return applyProbeIgnored(base, description);
+ } else {
+ return applyDefault(base, description);
+ }
+ }
+
+ /**
+ * Run the given {@link Statement} with no special treatment.
+ */
+ private Statement applyDefault(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
- if (description.getTestClass().getAnnotation(IgnoreUnderRavenwood.class) != null) {
- Assume.assumeFalse(IS_UNDER_RAVENWOOD);
- }
- if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
+ if (hasIgnoreUnderRavenwoodAnnotation(description)) {
Assume.assumeFalse(IS_UNDER_RAVENWOOD);
}
- if (IS_UNDER_RAVENWOOD) {
- RavenwoodRuleImpl.init(RavenwoodRule.this);
- }
+
+ RavenwoodRuleImpl.init(RavenwoodRule.this);
try {
base.evaluate();
} finally {
- if (IS_UNDER_RAVENWOOD) {
- RavenwoodRuleImpl.reset(RavenwoodRule.this);
+ RavenwoodRuleImpl.reset(RavenwoodRule.this);
+ }
+ }
+ };
+ }
+
+ /**
+ * Run the given {@link Statement} with probing enabled. All tests will be unconditionally
+ * run under Ravenwood to detect cases where a test is able to pass despite being marked as
+ * {@code IgnoreUnderRavenwood}.
+ */
+ private Statement applyProbeIgnored(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ RavenwoodRuleImpl.init(RavenwoodRule.this);
+ try {
+ base.evaluate();
+ } catch (Throwable t) {
+ if (hasIgnoreUnderRavenwoodAnnotation(description)) {
+ // This failure is expected, so eat the exception and report the
+ // assumption failure that test authors expect
+ Assume.assumeFalse(IS_UNDER_RAVENWOOD);
}
+ throw t;
+ } finally {
+ RavenwoodRuleImpl.reset(RavenwoodRule.this);
+ }
+
+ if (hasIgnoreUnderRavenwoodAnnotation(description) && IS_UNDER_RAVENWOOD) {
+ fail("Test was annotated with IgnoreUnderRavenwood, but it actually "
+ + "passed under Ravenwood; consider removing the annotation");
}
}
};
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index fb71e9d1ac6f..0ff6a1ad846b 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -22,12 +22,10 @@ public class RavenwoodRuleImpl {
}
public static void init(RavenwoodRule rule) {
- // Must be provided by impl to reference runtime internals
- throw new UnsupportedOperationException();
+ // No-op when running on a real device
}
public static void reset(RavenwoodRule rule) {
- // Must be provided by impl to reference runtime internals
- throw new UnsupportedOperationException();
+ // No-op when running on a real device
}
}
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 ab678d93c665..b5130a1c4cfc 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -27,3 +27,10 @@ flag {
description: "Mitigation for view state reset to empty causing no save dialog to show issue"
bug: "297976948"
}
+
+flag {
+ 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 09e79860b45c..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.
@@ -1426,14 +1426,19 @@ public abstract class PackageManagerInternal {
/**
* Checks if package is quarantined for a specific user.
+ *
+ * @throws PackageManager.NameNotFoundException if the package is not found
*/
- public abstract boolean isPackageQuarantined(@NonNull String packageName,
- @UserIdInt int userId);
+ public abstract boolean isPackageQuarantined(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException;
/**
* Checks if package is stopped for a specific user.
+ *
+ * @throws PackageManager.NameNotFoundException if the package is not found
*/
- public abstract boolean isPackageStopped(@NonNull String packageName, @UserIdInt int userId);
+ public abstract boolean isPackageStopped(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException;
/**
* Sends the PACKAGE_RESTARTED broadcast.
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/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 71916843fe0b..df8f17ac9d7c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -5175,6 +5175,8 @@ public final class ActiveServices {
return null;
}
+ final long startTimeNs = SystemClock.elapsedRealtimeNanos();
+
if (DEBUG_SERVICE) {
Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent + " fg=" + r.fgRequired);
}
@@ -5333,9 +5335,14 @@ public final class ActiveServices {
bringDownServiceLocked(r, enqueueOomAdj);
return msg;
}
+ mAm.mProcessList.getAppStartInfoTracker().handleProcessServiceStart(startTimeNs, app, r,
+ hostingRecord, true);
if (isolated) {
r.isolationHostProc = app;
}
+ } else {
+ mAm.mProcessList.getAppStartInfoTracker().handleProcessServiceStart(startTimeNs, app, r,
+ hostingRecord, false);
}
if (r.fgRequired) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ac173f3b5b7a..2ee39c577977 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -421,6 +421,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.policy.AttributeCache;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
@@ -468,7 +469,6 @@ import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.SELinuxUtil;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.snapshot.PackageDataSnapshot;
import com.android.server.power.stats.BatteryStatsImpl;
import com.android.server.sdksandbox.SdkSandboxManagerLocal;
@@ -1103,9 +1103,51 @@ public class ActivityManagerService extends IActivityManager.Stub
private final ActivityMetricsLaunchObserver mActivityLaunchObserver =
new ActivityMetricsLaunchObserver() {
+
+ @Override
+ public void onIntentStarted(@NonNull Intent intent, long timestampNanos) {
+ synchronized (this) {
+ mProcessList.getAppStartInfoTracker().onIntentStarted(intent, timestampNanos);
+ }
+ }
+
@Override
- public void onActivityLaunched(long id, ComponentName name, int temperature) {
+ public void onIntentFailed(long id) {
+ mProcessList.getAppStartInfoTracker().onIntentFailed(id);
+ }
+
+ @Override
+ public void onActivityLaunched(long id, ComponentName name, int temperature, int userId) {
mAppProfiler.onActivityLaunched();
+ synchronized (ActivityManagerService.this) {
+ ProcessRecord record = null;
+ try {
+ record = getProcessRecordLocked(name.getPackageName(), mContext
+ .getPackageManager().getPackageUidAsUser(name.getPackageName(), 0,
+ userId));
+ } catch (NameNotFoundException nnfe) {
+ // Ignore, record will be lost.
+ }
+ mProcessList.getAppStartInfoTracker().onActivityLaunched(id, name, temperature,
+ record);
+ }
+ }
+
+ @Override
+ public void onActivityLaunchCancelled(long id) {
+ mProcessList.getAppStartInfoTracker().onActivityLaunchCancelled(id);
+ }
+
+ @Override
+ public void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos,
+ int launchMode) {
+ mProcessList.getAppStartInfoTracker().onActivityLaunchFinished(id, name,
+ timestampNanos, launchMode);
+ }
+
+ @Override
+ public void onReportFullyDrawn(long id, long timestampNanos) {
+ mProcessList.getAppStartInfoTracker().onReportFullyDrawn(id, timestampNanos);
}
};
@@ -4488,13 +4530,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this")
private void attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
-
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
long bindApplicationTimeMillis;
+ long bindApplicationTimeNanos;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
@@ -4698,6 +4740,7 @@ public class ActivityManagerService extends IActivityManager.Stub
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
bindApplicationTimeMillis = SystemClock.uptimeMillis();
+ bindApplicationTimeNanos = SystemClock.elapsedRealtimeNanos();
mAtmInternal.preBindApplication(app.getWindowProcessController());
final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
if (mPlatformCompat != null) {
@@ -4754,6 +4797,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
app.setBindApplicationTime(bindApplicationTimeMillis);
+ mProcessList.getAppStartInfoTracker()
+ .reportBindApplicationTimeNanos(app, bindApplicationTimeNanos);
// Make app active after binding application or client may be running requests (e.g
// starting activities) before it is ready.
@@ -9799,12 +9844,12 @@ public class ActivityManagerService extends IActivityManager.Stub
final int uid = enforceDumpPermissionForPackage(packageName, userId, callingUid,
"getHistoricalProcessStartReasons");
if (uid != INVALID_UID) {
- mProcessList.mAppStartInfoTracker.getStartInfo(
+ mProcessList.getAppStartInfoTracker().getStartInfo(
packageName, userId, callingPid, maxNum, results);
}
} else {
// If no package name is given, use the caller's uid as the filter uid.
- mProcessList.mAppStartInfoTracker.getStartInfo(
+ mProcessList.getAppStartInfoTracker().getStartInfo(
packageName, callingUid, callingPid, maxNum, results);
}
return new ParceledListSlice<ApplicationStartInfo>(results);
@@ -9822,7 +9867,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final int callingUid = Binder.getCallingUid();
- mProcessList.mAppStartInfoTracker.addStartInfoCompleteListener(listener, callingUid);
+ mProcessList.getAppStartInfoTracker().addStartInfoCompleteListener(listener, callingUid);
}
@@ -9836,7 +9881,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final int callingUid = Binder.getCallingUid();
- mProcessList.mAppStartInfoTracker.clearStartInfoCompleteListener(callingUid, true);
+ mProcessList.getAppStartInfoTracker().clearStartInfoCompleteListener(callingUid, true);
}
@Override
@@ -10138,7 +10183,7 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
- mProcessList.mAppStartInfoTracker.dumpHistoryProcessStartInfo(pw, dumpPackage);
+ mProcessList.getAppStartInfoTracker().dumpHistoryProcessStartInfo(pw, dumpPackage);
pw.println("-------------------------------------------------------------------------------");
mProcessList.mAppExitInfoTracker.dumpHistoryProcessExitInfo(pw, dumpPackage);
}
@@ -10541,7 +10586,7 @@ public class ActivityManagerService extends IActivityManager.Stub
dumpPackage = args[opti];
opti++;
}
- mProcessList.mAppStartInfoTracker.dumpHistoryProcessStartInfo(pw, dumpPackage);
+ mProcessList.getAppStartInfoTracker().dumpHistoryProcessStartInfo(pw, dumpPackage);
} else if ("exit-info".equals(cmd)) {
if (opti < args.length) {
dumpPackage = args[opti];
@@ -13831,6 +13876,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// activity manager to announce its creation.
public boolean bindBackupAgent(String packageName, int backupMode, int targetUserId,
@BackupDestination int backupDestination) {
+ long startTimeNs = SystemClock.elapsedRealtimeNanos();
if (DEBUG_BACKUP) {
Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode
+ " targetUserId=" + targetUserId + " callingUid = " + Binder.getCallingUid()
@@ -13906,15 +13952,20 @@ public class ActivityManagerService extends IActivityManager.Stub
? new ComponentName(app.packageName, app.backupAgentName)
: new ComponentName("android", "FullBackupAgent");
- // startProcessLocked() returns existing proc's record if it's already running
- ProcessRecord proc = startProcessLocked(app.processName, app,
- false, 0,
- new HostingRecord(HostingRecord.HOSTING_TYPE_BACKUP, hostingName),
- ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS, false, false);
+ ProcessRecord proc = getProcessRecordLocked(app.processName, app.uid);
+ boolean isProcessStarted = proc != null;
+ if (!isProcessStarted) {
+ proc = startProcessLocked(app.processName, app,
+ false, 0,
+ new HostingRecord(HostingRecord.HOSTING_TYPE_BACKUP, hostingName),
+ ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS, false, false);
+ }
if (proc == null) {
Slog.e(TAG, "Unable to start backup agent process " + r);
return false;
}
+ mProcessList.getAppStartInfoTracker().handleProcessBackupStart(startTimeNs, proc, r,
+ !isProcessStarted);
// If the app is a regular app (uid >= 10000) and not the system server or phone
// process, etc, then mark it as being in full backup so that certain calls to the
@@ -18741,8 +18792,12 @@ public class ActivityManagerService extends IActivityManager.Stub
// If the process is known as top app, set a hint so when the process is
// started, the top priority can be applied immediately to avoid cpu being
// preempted by other processes before attaching the process of top app.
- startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
- new HostingRecord(hostingType, hostingName, isTop),
+ final long startTimeNs = SystemClock.elapsedRealtimeNanos();
+ HostingRecord hostingRecord =
+ new HostingRecord(hostingType, hostingName, isTop);
+ ProcessRecord rec = getProcessRecordLocked(processName, info.uid);
+ ProcessRecord app = startProcessLocked(processName, info, knownToBeDead,
+ 0 /* intentFlags */, hostingRecord,
ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
false /* isolated */);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index f3b2ef34ad6d..ae0cd65b2770 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1362,7 +1362,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
}
userId = user.id;
}
- mInternal.mProcessList.mAppStartInfoTracker
+ mInternal.mProcessList.getAppStartInfoTracker()
.clearHistoryProcessStartInfo(packageName, userId);
return 0;
}
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index edca74fae0e4..82e554e67b7e 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -22,11 +22,12 @@ import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import android.app.ActivityOptions;
+import android.annotation.NonNull;
import android.app.ApplicationStartInfo;
import android.app.Flags;
import android.app.IApplicationStartInfoCompleteListener;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -138,6 +139,15 @@ public final class AppStartInfoTracker {
/** The path to the historical proc start info file, persisted in the storage. */
@VisibleForTesting File mProcStartInfoFile;
+
+ /**
+ * Temporary list of records that have not been completed.
+ *
+ * Key is timestamp of launch from {@link #ActivityMetricsLaunchObserver}.
+ */
+ @GuardedBy("mLock")
+ private ArrayMap<Long, ApplicationStartInfo> mInProgRecords = new ArrayMap<>();
+
AppStartInfoTracker() {
mCallbacks = new SparseArray<>();
mData = new ProcessMap<AppStartInfoContainer>();
@@ -174,68 +184,99 @@ public final class AppStartInfoTracker {
});
}
- void handleProcessColdStarted(long startTimeNs, HostingRecord hostingRecord,
- ProcessRecord app) {
+ void onIntentStarted(@NonNull Intent intent, long timestampNanos) {
synchronized (mLock) {
if (!mEnabled) {
return;
}
ApplicationStartInfo start = new ApplicationStartInfo();
- addBaseFieldsFromProcessRecord(start, app);
start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
- start.addStartupTimestamp(
- ApplicationStartInfo.START_TIMESTAMP_LAUNCH, startTimeNs);
- start.addStartupTimestamp(
- ApplicationStartInfo.START_TIMESTAMP_FORK, app.getStartElapsedTime());
- start.setStartType(ApplicationStartInfo.START_TYPE_COLD);
- start.setReason(ApplicationStartInfo.START_REASON_OTHER);
- addStartInfoLocked(start);
+ start.setIntent(intent);
+ start.setStartType(ApplicationStartInfo.START_TYPE_UNSET);
+ start.addStartupTimestamp(ApplicationStartInfo.START_TIMESTAMP_LAUNCH, timestampNanos);
+ if (intent != null && intent.getCategories() != null
+ && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
+ start.setReason(ApplicationStartInfo.START_REASON_LAUNCHER);
+ } else {
+ start.setReason(ApplicationStartInfo.START_REASON_START_ACTIVITY);
+ }
+ mInProgRecords.put(timestampNanos, start);
}
}
- public void handleProcessActivityWarmOrHotStarted(long startTimeNs,
- ActivityOptions activityOptions, Intent intent) {
+ void onIntentFailed(long id) {
synchronized (mLock) {
if (!mEnabled) {
return;
}
- ApplicationStartInfo start = new ApplicationStartInfo();
- start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
- start.addStartupTimestamp(
- ApplicationStartInfo.START_TIMESTAMP_LAUNCH, startTimeNs);
- start.setIntent(intent);
- start.setReason(ApplicationStartInfo.START_REASON_LAUNCHER);
- if (activityOptions != null) {
- start.setProcessName(activityOptions.getPackageName());
+ if (!mInProgRecords.containsKey(id)) {
+ return;
}
- start.setStartType(ApplicationStartInfo.START_TYPE_WARM);
- if (intent != null && intent.getCategories() != null
- && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
- start.setReason(ApplicationStartInfo.START_REASON_LAUNCHER);
+ mInProgRecords.get(id).setStartupState(ApplicationStartInfo.STARTUP_STATE_ERROR);
+ mInProgRecords.remove(id);
+ }
+ }
+
+ void onActivityLaunched(long id, ComponentName name, long temperature, ProcessRecord app) {
+ synchronized (mLock) {
+ if (!mEnabled) {
+ return;
+ }
+ if (!mInProgRecords.containsKey(id)) {
+ return;
+ }
+ if (app != null) {
+ ApplicationStartInfo info = mInProgRecords.get(id);
+ info.setStartType((int) temperature);
+ addBaseFieldsFromProcessRecord(info, app);
+ addStartInfoLocked(info);
} else {
- start.setReason(ApplicationStartInfo.START_REASON_START_ACTIVITY);
+ mInProgRecords.remove(id);
}
- addStartInfoLocked(start);
}
}
- public void handleProcessActivityStartedFromRecents(long startTimeNs,
- ActivityOptions activityOptions) {
+ void onActivityLaunchCancelled(long id) {
synchronized (mLock) {
if (!mEnabled) {
return;
}
- ApplicationStartInfo start = new ApplicationStartInfo();
- start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
- start.addStartupTimestamp(
- ApplicationStartInfo.START_TIMESTAMP_LAUNCH, startTimeNs);
- if (activityOptions != null) {
- start.setIntent(activityOptions.getResultData());
- start.setProcessName(activityOptions.getPackageName());
+ if (!mInProgRecords.containsKey(id)) {
+ return;
}
- start.setReason(ApplicationStartInfo.START_REASON_LAUNCHER_RECENTS);
- start.setStartType(ApplicationStartInfo.START_TYPE_WARM);
- addStartInfoLocked(start);
+ ApplicationStartInfo info = mInProgRecords.get(id);
+ info.setStartupState(ApplicationStartInfo.STARTUP_STATE_ERROR);
+ mInProgRecords.remove(id);
+ }
+ }
+
+ void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos,
+ int launchMode) {
+ synchronized (mLock) {
+ if (!mEnabled) {
+ return;
+ }
+ if (!mInProgRecords.containsKey(id)) {
+ return;
+ }
+ ApplicationStartInfo info = mInProgRecords.get(id);
+ info.setStartupState(ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN);
+ info.setLaunchMode(launchMode);
+ }
+ }
+
+ void onReportFullyDrawn(long id, long timestampNanos) {
+ synchronized (mLock) {
+ if (!mEnabled) {
+ return;
+ }
+ if (!mInProgRecords.containsKey(id)) {
+ return;
+ }
+ ApplicationStartInfo info = mInProgRecords.get(id);
+ info.addStartupTimestamp(ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN,
+ timestampNanos);
+ mInProgRecords.remove(id);
}
}
@@ -347,7 +388,8 @@ public final class AppStartInfoTracker {
ApplicationStartInfo.START_TIMESTAMP_APPLICATION_ONCREATE);
}
- void reportBindApplicationTimeNanos(ProcessRecord app, long timeNs) {
+ /** Report a bind application timestamp to add to {@link ApplicationStartInfo}. */
+ public void reportBindApplicationTimeNanos(ProcessRecord app, long timeNs) {
addTimestampToStart(app, timeNs,
ApplicationStartInfo.START_TIMESTAMP_BIND_APPLICATION);
}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 903cb7bcfaed..982076dd7c9a 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -30,7 +30,6 @@ import android.widget.WidgetFlags;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import java.util.ArrayList;
import java.util.HashMap;
@@ -164,12 +163,6 @@ final class CoreSettingsObserver extends ContentObserver {
WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT));
sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION,
- SystemUiDeviceConfigFlags.KEY_REMOTEVIEWS_ADAPTER_CONVERSION, boolean.class,
- SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT));
-
- sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
TextFlags.NAMESPACE, TextFlags.ENABLE_NEW_CONTEXT_MENU,
TextFlags.KEY_ENABLE_NEW_CONTEXT_MENU, boolean.class,
TextFlags.ENABLE_NEW_CONTEXT_MENU_DEFAULT));
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4ff34b1d7faa..3156e9da0ae9 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -498,7 +498,7 @@ public final class ProcessList {
/** Manages the {@link android.app.ApplicationStartInfo} records. */
@GuardedBy("mAppStartInfoTracker")
- final AppStartInfoTracker mAppStartInfoTracker = new AppStartInfoTracker();
+ private final AppStartInfoTracker mAppStartInfoTracker = new AppStartInfoTracker();
/**
* The currently running SDK sandbox processes for a uid.
@@ -1523,6 +1523,10 @@ public final class ProcessList {
return mCachedRestoreLevel;
}
+ AppStartInfoTracker getAppStartInfoTracker() {
+ return mAppStartInfoTracker;
+ }
+
/**
* Set the out-of-memory badness adjustment for a process.
* If {@code pid <= 0}, this method will be a no-op.
@@ -2572,6 +2576,7 @@ public final class ProcessList {
boolean isSdkSandbox, int sdkSandboxUid, String sdkSandboxClientAppPackage,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
long startTime = SystemClock.uptimeMillis();
+ final long startTimeNs = SystemClock.elapsedRealtimeNanos();
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid);
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/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index b1825380bbdc..32d5cf587e0c 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -152,7 +152,6 @@ public final class GameManagerService extends IGameManagerService.Stub {
private static final String GAME_MODE_INTERVENTION_LIST_FILE_NAME =
"game_mode_intervention.list";
-
private final Context mContext;
private final Object mLock = new Object();
private final Object mDeviceConfigLock = new Object();
@@ -184,6 +183,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
@GuardedBy("mUidObserverLock")
private final Set<Integer> mForegroundGameUids = new HashSet<>();
private final GameManagerServiceSystemPropertiesWrapper mSysProps;
+ private float mGameDefaultFrameRateValue;
@VisibleForTesting
static class Injector {
@@ -1559,6 +1559,10 @@ public final class GameManagerService extends IGameManagerService.Stub {
mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, false);
Slog.v(TAG, "Game power mode OFF (game manager service start/restart)");
mPowerManagerInternal.setPowerMode(Mode.GAME, false);
+
+ mGameDefaultFrameRateValue = (float) mSysProps.getInt(
+ PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE, 60);
+ Slog.v(TAG, "Game Default Frame Rate : " + mGameDefaultFrameRateValue);
}
private void sendUserMessage(int userId, int what, String eventForLog, int delayMillis) {
@@ -2217,8 +2221,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
if (gameDefaultFrameRate()) {
gameDefaultFrameRate = isGameDefaultFrameRateEnabled
- ? (float) mSysProps.getInt(
- PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE, 0) : 0.0f;
+ ? mGameDefaultFrameRateValue : 0.0f;
}
return gameDefaultFrameRate;
}
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/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 44cb1367928d..290bb7e92c69 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5106,7 +5106,7 @@ public class AudioService extends IAudioService.Stub
private void setMasterMuteInternalNoCallerCheck(
boolean mute, int flags, int userId, String eventSource) {
if (DEBUG_VOL) {
- Log.d(TAG, TextUtils.formatSimple("Master mute %s, %d, user=%d from %s",
+ Log.d(TAG, TextUtils.formatSimple("Master mute %s, flags 0x%x, userId=%d from %s",
mute, flags, userId, eventSource));
}
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/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 5084b602bff2..578d9dc2aede 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -722,6 +722,7 @@ public class FaceService extends SystemService {
if (Flags.faceVhalFeature() && Utils.isVirtualEnabled(getContext())) {
if (virtualAt != -1) {
//only virtual instance should be returned
+ Slog.i(TAG, "virtual hal is used");
return new Pair(new ArrayList<>(), List.of(aidlInstances.get(virtualAt)));
} else {
Slog.e(TAG, "Could not find virtual interface while it is enabled");
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 5ce0c8b384ef..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);
}
@@ -1057,6 +1082,7 @@ public class FingerprintService extends SystemService {
if (Utils.isVirtualEnabled(getContext())) {
if (virtualAt != -1) {
//only virtual instance should be returned
+ Slog.i(TAG, "virtual hal is used");
return new Pair(new ArrayList<>(), List.of(aidlInstances.get(virtualAt)));
} else {
Slog.e(TAG, "Could not find virtual interface while it is enabled");
@@ -1085,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/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 1e5e147749a2..df179a9b6d65 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1294,8 +1294,8 @@ public class SyncManager {
if (android.content.pm.Flags.stayStopped()) {
try {
return mPackageManagerInternal.isPackageStopped(packageName, userId);
- } catch (IllegalArgumentException e) {
- Log.d(TAG, "Couldn't determine stopped state for unknown package: " + packageName);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Couldn't determine stopped state for unknown package: " + packageName);
}
}
return false;
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/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 168715713f8d..5831b29437dc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -194,10 +194,14 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
addAndStartAction(new RequestActiveSourceAction(this, new IHdmiControlCallback.Stub() {
@Override
public void onComplete(int result) {
- if (result != HdmiControlManager.RESULT_SUCCESS) {
+ if (!mService.getLocalActiveSource().isValid()
+ && result != HdmiControlManager.RESULT_SUCCESS) {
mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
getDeviceInfo().getLogicalAddress(),
getDeviceInfo().getPhysicalAddress()));
+ updateActiveSource(getDeviceInfo().getLogicalAddress(),
+ getDeviceInfo().getPhysicalAddress(),
+ "RequestActiveSourceAction#finishWithCallback()");
}
}
}));
@@ -257,6 +261,7 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
if (isAlreadyActiveSource(targetDevice, targetAddress, callback)) {
return;
}
+ removeAction(RequestActiveSourceAction.class);
if (targetAddress == Constants.ADDR_INTERNAL) {
handleSelectInternalSource();
// Switching to internal source is always successful even when CEC control is disabled.
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index f526dbe9c66d..4089a81dfc20 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -215,10 +215,20 @@ public abstract class InputMethodManagerInternal {
/**
* Switch the keyboard layout in response to a keyboard shortcut.
*
- * @param direction {@code 1} to switch to the next subtype, {@code -1} to switch to the
- * previous subtype
+ * @param direction {@code 1} to switch to the next subtype, {@code -1} to switch to the
+ * previous subtype
+ * @param displayId the display to which the keyboard layout switch shortcut is
+ * dispatched. Note that there is no guarantee that an IME is
+ * associated with this display. This is more or less than a hint for
+ * cases when no IME is running for the given targetWindowToken. There
+ * is a longstanding discussion whether we should allow users to
+ * rotate keyboard layout even when there is no edit field, and this
+ * displayID would be helpful for such a situation.
+ * @param targetWindowToken the window token to which other keys are being sent while handling
+ * this shortcut.
*/
- public abstract void switchKeyboardLayout(int direction);
+ public abstract void onSwitchKeyboardLayoutShortcut(int direction, int displayId,
+ IBinder targetWindowToken);
/**
* Returns true if any InputConnection is currently active.
@@ -314,7 +324,8 @@ public abstract class InputMethodManagerInternal {
}
@Override
- public void switchKeyboardLayout(int direction) {
+ public void onSwitchKeyboardLayoutShortcut(int direction, int displayId,
+ IBinder targetWindowToken) {
}
@Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 30e9f5bd2a14..16e043cfb64d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5763,7 +5763,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
- public void switchKeyboardLayout(int direction) {
+ public void onSwitchKeyboardLayoutShortcut(int direction, int displayId,
+ IBinder targetWindowToken) {
synchronized (ImfLock.class) {
switchKeyboardLayoutLocked(direction);
}
@@ -6498,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/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index ec858ee296e1..f2dcba45e312 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -59,6 +59,7 @@ import android.util.apk.SourceStampVerifier;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
@@ -67,7 +68,6 @@ import com.android.server.integrity.model.IntegrityCheckResult;
import com.android.server.integrity.model.RuleMetadata;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index bab3cbea108e..9c27c22dfd00 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -18,6 +18,7 @@ package com.android.server.location.contexthub;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.contexthub.HostEndpointInfo;
+import android.hardware.contexthub.MessageDeliveryStatus;
import android.hardware.contexthub.NanSessionRequest;
import android.hardware.contexthub.V1_0.ContextHub;
import android.hardware.contexthub.V1_0.ContextHubMsg;
@@ -467,6 +468,11 @@ public abstract class IContextHubWrapper {
// TODO(271471342): Implement
}
+ public void handleMessageDeliveryStatus(char hostEndPointId,
+ MessageDeliveryStatus messageDeliveryStatus) {
+ // TODO(b/312417087): Implement reliable message support
+ }
+
public byte[] getUuid() {
return UUID;
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 42c2548264d4..0c2eee5aebbe 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -209,7 +209,7 @@ import javax.crypto.spec.GCMParameterSpec;
* <li>Protect each user's data using their SP. For example, use the SP to encrypt/decrypt the
* user's credential-encrypted (CE) key for file-based encryption (FBE).</li>
*
- * <li>Generate, protect, and use profile passwords for managed profiles.</li>
+ * <li>Generate, protect, and use unified profile passwords.</li>
*
* <li>Support unlocking the SP by alternative means: resume-on-reboot (reboot escrow) for easier
* OTA updates, and escrow tokens when set up by the Device Policy Controller (DPC).</li>
@@ -287,7 +287,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private final java.security.KeyStore mJavaKeyStore;
private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
- private ManagedProfilePasswordCache mManagedProfilePasswordCache;
+ private final UnifiedProfilePasswordCache mUnifiedProfilePasswordCache;
private final RebootEscrowManager mRebootEscrowManager;
@@ -404,7 +404,8 @@ public class LockSettingsService extends ILockSettings.Stub {
for (int i = 0; i < newPasswordChars.length; i++) {
newPassword[i] = (byte) newPasswordChars[i];
}
- LockscreenCredential credential = LockscreenCredential.createManagedPassword(newPassword);
+ LockscreenCredential credential =
+ LockscreenCredential.createUnifiedProfilePassword(newPassword);
Arrays.fill(newPasswordChars, '\u0000');
Arrays.fill(newPassword, (byte) 0);
Arrays.fill(randomLockSeed, (byte) 0);
@@ -424,7 +425,7 @@ public class LockSettingsService extends ILockSettings.Stub {
if (!isCredentialSharableWithParent(profileUserId)) {
return;
}
- // Do not tie profile when work challenge is enabled
+ // Do not tie profile when separate challenge is enabled
if (getSeparateProfileChallengeEnabledInternal(profileUserId)) {
return;
}
@@ -462,7 +463,7 @@ public class LockSettingsService extends ILockSettings.Stub {
setLockCredentialInternal(unifiedProfilePassword, profileUserPassword, profileUserId,
/* isLockTiedToParent= */ true);
tieProfileLockToParent(profileUserId, parent.id, unifiedProfilePassword);
- mManagedProfilePasswordCache.storePassword(profileUserId, unifiedProfilePassword,
+ mUnifiedProfilePasswordCache.storePassword(profileUserId, unifiedProfilePassword,
parentSid);
}
}
@@ -620,9 +621,9 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache(
+ public @NonNull UnifiedProfilePasswordCache getUnifiedProfilePasswordCache(
java.security.KeyStore ks) {
- return new ManagedProfilePasswordCache(ks);
+ return new UnifiedProfilePasswordCache(ks);
}
public boolean isHeadlessSystemUserMode() {
@@ -665,7 +666,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mGatekeeperPasswords = new LongSparseArray<>();
mSpManager = injector.getSyntheticPasswordManager(mStorage);
- mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache(mJavaKeyStore);
+ mUnifiedProfilePasswordCache = injector.getUnifiedProfilePasswordCache(mJavaKeyStore);
mBiometricDeferredQueue = new BiometricDeferredQueue(mSpManager, mHandler);
mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(),
@@ -689,8 +690,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
/**
- * If the account is credential-encrypted, show notification requesting the user to unlock the
- * device.
+ * If the user is a managed profile whose credential-encrypted storage is locked, show a
+ * notification requesting the user to unlock the device.
*/
private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId, String reason) {
final UserInfo user = mUserManager.getUserInfo(userId);
@@ -846,7 +847,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mHandler.post(new Runnable() {
@Override
public void run() {
- // Hide notification first, as tie managed profile lock takes time
+ // Hide notification first, as tie profile lock takes time
hideEncryptionNotification(new UserHandle(userId));
if (isCredentialSharableWithParent(userId)) {
@@ -1458,13 +1459,13 @@ public class LockSettingsService extends ILockSettings.Stub {
cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
decryptionResult = cipher.doFinal(encryptedPassword);
- LockscreenCredential credential = LockscreenCredential.createManagedPassword(
+ LockscreenCredential credential = LockscreenCredential.createUnifiedProfilePassword(
decryptionResult);
Arrays.fill(decryptionResult, (byte) 0);
try {
long parentSid = getGateKeeperService().getSecureUserId(
mUserManager.getProfileParent(userId).id);
- mManagedProfilePasswordCache.storePassword(userId, credential, parentSid);
+ mUnifiedProfilePasswordCache.storePassword(userId, credential, parentSid);
} catch (RemoteException e) {
Slogf.w(TAG, "Failed to talk to GateKeeper service", e);
}
@@ -1550,7 +1551,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// so it goes into the cache
getDecryptedPasswordForTiedProfile(profile.id);
} catch (GeneralSecurityException | IOException e) {
- Slog.d(TAG, "Cache work profile password failed", e);
+ Slog.d(TAG, "Cache unified profile password failed", e);
}
}
}
@@ -1604,19 +1605,19 @@ public class LockSettingsService extends ILockSettings.Stub {
}
/**
- * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
+ * Synchronize all profile's challenge of the given user if it's unified: tie or clear them
* depending on the parent user's secure state.
*
- * When clearing tied work challenges, a pre-computed password table for profiles are required,
- * since changing password for profiles requires existing password, and existing passwords can
- * only be computed before the parent user's password is cleared.
+ * When clearing tied challenges, a pre-computed password table for profiles are required, since
+ * changing password for profiles requires existing password, and existing passwords can only be
+ * computed before the parent user's password is cleared.
*
* Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
* method again on profiles. However the recursion is guaranteed to terminate as this method
* terminates when the user is a profile that shares lock credentials with parent.
* (e.g. managed and clone profile).
*/
- private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
+ private void synchronizeUnifiedChallengeForProfiles(int userId,
Map<Integer, LockscreenCredential> profilePasswordMap) {
if (isCredentialSharableWithParent(userId)) {
return;
@@ -1635,7 +1636,7 @@ public class LockSettingsService extends ILockSettings.Stub {
tieProfileLockIfNecessary(profileUserId,
LockscreenCredential.createNone());
} else {
- // We use cached work profile password computed before clearing the parent's
+ // We use cached profile password computed before clearing the parent's
// credential, otherwise they get lost
if (profilePasswordMap != null
&& profilePasswordMap.containsKey(profileUserId)) {
@@ -1777,7 +1778,7 @@ public class LockSettingsService extends ILockSettings.Stub {
notifyPasswordChanged(credential, userId);
}
if (isCredentialSharableWithParent(userId)) {
- // Make sure the profile doesn't get locked straight after setting work challenge.
+ // Make sure the profile doesn't get locked straight after setting challenge.
setDeviceUnlockedForUser(userId);
}
notifySeparateProfileChallengeChanged(userId);
@@ -2368,7 +2369,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
try {
- // Unlock work profile, and work profile with unified lock must use password only
+ // Unlock profile with unified lock
return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
userId, null /* progressCallback */, flags);
} catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
@@ -2492,7 +2493,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mStrongAuth.removeUser(userId);
AndroidKeyStoreMaintenance.onUserRemoved(userId);
- mManagedProfilePasswordCache.removePassword(userId);
+ mUnifiedProfilePasswordCache.removePassword(userId);
gateKeeperClearSecureUserId(userId);
removeKeystoreProfileKey(userId);
@@ -2982,7 +2983,7 @@ public class LockSettingsService extends ILockSettings.Stub {
credential, sp, userId);
final Map<Integer, LockscreenCredential> profilePasswords;
if (!credential.isNone()) {
- // not needed by synchronizeUnifiedWorkChallengeForProfiles()
+ // not needed by synchronizeUnifiedChallengeForProfiles()
profilePasswords = null;
if (!mSpManager.hasSidForUser(userId)) {
@@ -2993,8 +2994,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
} else {
- // Cache all profile password if they use unified work challenge. This will later be
- // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles()
+ // Cache all profile password if they use unified challenge. This will later be used to
+ // clear the profile's password in synchronizeUnifiedChallengeForProfiles().
profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId);
mSpManager.clearSidForUser(userId);
@@ -3010,10 +3011,10 @@ public class LockSettingsService extends ILockSettings.Stub {
}
setCurrentLskfBasedProtectorId(newProtectorId, userId);
LockPatternUtils.invalidateCredentialTypeCache();
- synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
+ synchronizeUnifiedChallengeForProfiles(userId, profilePasswords);
setUserPasswordMetrics(credential, userId);
- mManagedProfilePasswordCache.removePassword(userId);
+ mUnifiedProfilePasswordCache.removePassword(userId);
if (savedCredentialType != CREDENTIAL_TYPE_NONE) {
mSpManager.destroyAllWeakTokenBasedProtectors(userId);
}
@@ -3114,7 +3115,7 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
currentCredential = getDecryptedPasswordForTiedProfile(userId);
} catch (Exception e) {
- Slog.e(TAG, "Failed to get work profile credential", e);
+ Slog.e(TAG, "Failed to get unified profile password", e);
return null;
}
}
@@ -3284,7 +3285,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public boolean tryUnlockWithCachedUnifiedChallenge(int userId) {
checkPasswordReadPermission();
- try (LockscreenCredential cred = mManagedProfilePasswordCache.retrievePassword(userId)) {
+ try (LockscreenCredential cred = mUnifiedProfilePasswordCache.retrievePassword(userId)) {
if (cred == null) {
return false;
}
@@ -3296,7 +3297,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public void removeCachedUnifiedChallenge(int userId) {
checkWritePermission();
- mManagedProfilePasswordCache.removePassword(userId);
+ mUnifiedProfilePasswordCache.removePassword(userId);
}
static String timestampToString(long timestamp) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 1e8b387fc189..6d123ccebc7c 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -501,10 +501,10 @@ class LockSettingsStorage {
final UserInfo parentInfo = um.getProfileParent(userId);
if (parentInfo == null) {
- // This user owns its lock settings files - safe to delete them
+ // Delete files specific to non-profile users.
deleteFile(getRebootEscrowFile(userId));
} else {
- // Managed profile
+ // Delete files specific to profile users.
removeChildProfileLock(userId);
}
diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/UnifiedProfilePasswordCache.java
index 1298fe8f07a4..21caf76d30d0 100644
--- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
+++ b/services/core/java/com/android/server/locksettings/UnifiedProfilePasswordCache.java
@@ -43,30 +43,31 @@ import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
/**
- * Caches *unified* work challenge for managed profiles. The cached credential is encrypted using
- * a keystore key auth-bound to the parent user's lockscreen credential, similar to how unified
- * work challenge is normally secured.
- *
- * <p> The cache is filled whenever the managed profile's unified challenge is created or derived
- * (as part of the parent user's credential verification flow). It's removed when the profile is
- * deleted or a (separate) lockscreen credential is explicitly set on the profile. There is also
- * an ADB command to evict the cache "cmd lock_settings remove-cache --user X", to assist
- * development and testing.
-
- * <p> The encrypted credential is stored in-memory only so the cache does not persist across
- * reboots.
+ * An in-memory cache for unified profile passwords. A "unified profile password" is the random
+ * password that the system automatically generates and manages for each profile that uses a unified
+ * challenge and where the parent user has a secure lock screen.
+ * <p>
+ * Each password in this cache is encrypted by a Keystore key that is auth-bound to the parent user.
+ * This is very similar to how the password is protected on-disk, but the in-memory cache uses a
+ * much longer timeout on the keys: 7 days instead of 30 seconds. This enables use cases like
+ * unpausing work apps without requiring authentication as frequently.
+ * <p>
+ * Unified profile passwords are cached when they are created, or when they are decrypted as part of
+ * the parent user's LSKF verification flow. They are removed when the profile is deleted or when a
+ * separate challenge is explicitly set on the profile. There is also an ADB command to evict a
+ * cached password, "locksettings remove-cache --user X", to assist development and testing.
*/
@VisibleForTesting // public visibility is needed for Mockito
-public class ManagedProfilePasswordCache {
+public class UnifiedProfilePasswordCache {
- private static final String TAG = "ManagedProfilePasswordCache";
+ private static final String TAG = "UnifiedProfilePasswordCache";
private static final int KEY_LENGTH = 256;
private static final int CACHE_TIMEOUT_SECONDS = (int) TimeUnit.DAYS.toSeconds(7);
private final SparseArray<byte[]> mEncryptedPasswords = new SparseArray<>();
private final KeyStore mKeyStore;
- public ManagedProfilePasswordCache(KeyStore keyStore) {
+ public UnifiedProfilePasswordCache(KeyStore keyStore) {
mKeyStore = keyStore;
}
@@ -151,7 +152,8 @@ public class ManagedProfilePasswordCache {
Slog.d(TAG, "Cannot decrypt", e);
return null;
}
- LockscreenCredential result = LockscreenCredential.createManagedPassword(credential);
+ LockscreenCredential result =
+ LockscreenCredential.createUnifiedProfilePassword(credential);
Arrays.fill(credential, (byte) 0);
return result;
}
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 a62d8b8bc032..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;
@@ -5406,6 +5407,7 @@ public class NotificationManagerService extends SystemService {
private void validateAutomaticZenRule(AutomaticZenRule rule) {
Objects.requireNonNull(rule, "automaticZenRule is null");
Objects.requireNonNull(rule.getName(), "Name is null");
+ rule.validate();
if (rule.getOwner() == null
&& rule.getConfigurationActivity() == null) {
throw new NullPointerException(
@@ -5463,6 +5465,7 @@ public class NotificationManagerService extends SystemService {
public void setAutomaticZenRuleState(String id, Condition condition) {
Objects.requireNonNull(id, "id is null");
Objects.requireNonNull(condition, "Condition is null");
+ condition.validate();
enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
@@ -6962,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/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 7ec94c315798..3f8b5952a1bc 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -627,6 +627,7 @@ public class ZenModeHelper {
try {
ApplicationInfo applicationInfo = mPm.getApplicationInfo(pkg, 0);
rule.name = applicationInfo.loadLabel(mPm).toString();
+ rule.iconResName = drawableResIdToResName(pkg, applicationInfo.icon);
} catch (PackageManager.NameNotFoundException e) {
// Should not happen, since it's the app calling us (?)
Log.w(TAG, "Package not found for creating implicit zen rule");
@@ -634,6 +635,9 @@ public class ZenModeHelper {
}
});
+ rule.type = AutomaticZenRule.TYPE_OTHER;
+ rule.triggerDescription = mContext.getString(R.string.zen_mode_implicit_trigger_description,
+ rule.name);
rule.condition = null;
rule.conditionId = new Uri.Builder()
.scheme(Condition.SCHEME)
diff --git a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
index f985b5b64e21..b9b09fb0e84c 100644
--- a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
@@ -754,9 +754,9 @@ public class PersistentDataBlockService extends SystemService {
}
};
- private PersistentDataBlockManagerInternal mInternalService =
- new PersistentDataBlockManagerInternal() {
+ private InternalService mInternalService = new InternalService();
+ private class InternalService implements PersistentDataBlockManagerInternal {
@Override
public void setFrpCredentialHandle(byte[] handle) {
writeInternal(handle, getFrpCredentialDataOffset(), MAX_FRP_CREDENTIAL_HANDLE_SIZE);
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 bd725ed49f3c..482807c397ea 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -508,14 +508,19 @@ public interface Computer extends PackageDataSnapshot {
boolean getApplicationHiddenSettingAsUser(@NonNull String packageName, @UserIdInt int userId);
- boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId);
+ boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException;
- boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId);
+ boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException;
/** Check if the package is in a stopped state for a given user. */
- boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId);
+ 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 2dc3fb7464fd..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<>();
}
@@ -4980,40 +4977,45 @@ public class ComputerEngine implements Computer {
}
}
- private PackageUserStateInternal getUserStageOrDefaultForUser(@NonNull String packageName,
- int userId) {
+ private PackageUserStateInternal getUserStateOrDefaultForUser(@NonNull String packageName,
+ int userId) throws PackageManager.NameNotFoundException {
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "when asking about packages for user " + userId);
final PackageStateInternal ps = mSettings.getPackage(packageName);
if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
- throw new IllegalArgumentException("Unknown target package: " + packageName);
+ throw new PackageManager.NameNotFoundException(packageName);
}
return ps.getUserStateOrDefault(userId);
}
@Override
- public boolean isPackageSuspendedForUser(@NonNull String packageName, int userId) {
- return getUserStageOrDefaultForUser(packageName, userId).isSuspended();
+ public boolean isPackageSuspendedForUser(@NonNull String packageName, int userId)
+ throws PackageManager.NameNotFoundException {
+ return getUserStateOrDefaultForUser(packageName, userId).isSuspended();
}
@Override
- public boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId) {
- return getUserStageOrDefaultForUser(packageName, userId).isQuarantined();
+ public boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException {
+ return getUserStateOrDefaultForUser(packageName, userId).isQuarantined();
}
@Override
- public boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId) {
- return getUserStageOrDefaultForUser(packageName, userId).isStopped();
+ public boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException {
+ return getUserStateOrDefaultForUser(packageName, userId).isStopped();
}
@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/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
index 24a33f1949fa..e3bbd2d8d17e 100644
--- a/services/core/java/com/android/server/pm/IPackageManagerBase.java
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -951,20 +951,32 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@Deprecated
public final boolean isPackageSuspendedForUser(@NonNull String packageName,
@UserIdInt int userId) {
- return snapshot().isPackageSuspendedForUser(packageName, userId);
+ try {
+ return snapshot().isPackageSuspendedForUser(packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown target package: " + packageName);
+ }
}
@Override
@Deprecated
public final boolean isPackageQuarantinedForUser(@NonNull String packageName,
@UserIdInt int userId) {
- return snapshot().isPackageQuarantinedForUser(packageName, userId);
+ try {
+ return snapshot().isPackageQuarantinedForUser(packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown target package: " + packageName);
+ }
}
@Override
public final boolean isPackageStoppedForUser(@NonNull String packageName,
@UserIdInt int userId) {
- return snapshot().isPackageStoppedForUser(packageName, userId);
+ try {
+ return snapshot().isPackageStoppedForUser(packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown target package: " + packageName);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 5c4447eb99a4..3b9f9c804e27 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -18,6 +18,7 @@ package com.android.server.pm;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.PARSE_APK_IN_APEX;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
@@ -30,7 +31,6 @@ import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
-import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_APK_IN_APEX;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -46,12 +46,12 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.om.OverlayConfig;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.EventLogTags;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedArrayMap;
import java.io.File;
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index f1c062763183..0fa7aa5473b2 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -154,12 +154,16 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.F2fsUtils;
+import com.android.internal.pm.parsing.PackageParserException;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.security.VerityUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -181,8 +185,6 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedLibraryWrapper;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.security.FileIntegrityService;
import com.android.server.utils.WatchedArrayMap;
@@ -1165,7 +1167,7 @@ final class InstallPackageHelper {
parseFlags);
archivedPackage = request.getPackageLite().getArchivedPackage();
}
- } catch (PackageManagerException e) {
+ } catch (PackageManagerException | PackageParserException e) {
throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -2450,9 +2452,9 @@ final class InstallPackageHelper {
// Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
mAppDataHelper.prepareAppDataPostCommitLIF(ps, 0, installRequest.getNewUsers());
if (installRequest.isClearCodeCache()) {
- mAppDataHelper.clearAppDataLeafLIF(packageName, ps.getVolumeUuid(),
- UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
- | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ mAppDataHelper.clearAppDataLIF(ps.getPkg(), UserHandle.USER_ALL,
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
+ | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
if (installRequest.isInstallReplace() && pkg != null) {
mDexManager.notifyPackageUpdated(packageName,
@@ -2910,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;
@@ -3856,7 +3859,7 @@ final class InstallPackageHelper {
synchronized (mPm.mLock) {
platformPackage = mPm.getPlatformPackage();
- var isSystemApp = AndroidPackageUtils.isSystem(parsedPackage);
+ var isSystemApp = AndroidPackageLegacyUtils.isSystem(parsedPackage);
final String renamedPkgName = mPm.mSettings.getRenamedPackageLPr(
AndroidPackageUtils.getRealPackageOrNull(parsedPackage, isSystemApp));
realPkgName = ScanPackageUtils.getRealPackageName(parsedPackage, renamedPkgName,
@@ -4574,7 +4577,7 @@ final class InstallPackageHelper {
private void assertPackageWithSharedUserIdIsPrivileged(AndroidPackage pkg)
throws PackageManagerException {
- if (!AndroidPackageUtils.isPrivileged(pkg) && (pkg.getSharedUserId() != null)) {
+ if (!AndroidPackageLegacyUtils.isPrivileged(pkg) && (pkg.getSharedUserId() != null)) {
SharedUserSetting sharedUserSetting = null;
try {
synchronized (mPm.mLock) {
@@ -4612,7 +4615,7 @@ final class InstallPackageHelper {
final boolean skipVendorPrivilegeScan = ((scanFlags & SCAN_AS_VENDOR) != 0)
&& ScanPackageUtils.getVendorPartitionVersion() < 28;
if (((scanFlags & SCAN_AS_PRIVILEGED) == 0)
- && !AndroidPackageUtils.isPrivileged(pkg)
+ && !AndroidPackageLegacyUtils.isPrivileged(pkg)
&& (pkg.getSharedUserId() != null)
&& !skipVendorPrivilegeScan) {
SharedUserSetting sharedUserSetting = null;
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 5494bd9808c8..ee780d99b6b6 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -51,12 +51,12 @@ import android.util.ExceptionUtils;
import android.util.Slog;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.art.model.DexoptResult;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
import java.util.ArrayList;
@@ -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 58c1c0564f95..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);
}
@@ -1575,6 +1575,57 @@ public class LauncherAppsService extends SystemService {
}
@Override
+ public List<String> getPreInstalledSystemPackages(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 preinstalled packages for another user")) {
+ return null;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ String userType = mUm.getUserInfo(user.getIdentifier()).userType;
+ Set<String> preInstalledPackages = mUm.getPreInstallableSystemPackages(userType);
+ if (preInstalledPackages == null) {
+ return new ArrayList<>();
+ }
+ return List.copyOf(preInstalledPackages);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @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 e3bab3f243c3..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,
@@ -323,6 +323,7 @@ public class PackageArchiver {
PackageStateInternal ps = getPackageState(packageName, snapshot,
Binder.getCallingUid(), userId);
verifyNotSystemApp(ps.getFlags());
+ verifyInstalled(ps, userId);
String responsibleInstallerPackage = getResponsibleInstallerPackage(ps);
verifyInstaller(responsibleInstallerPackage, userId);
ApplicationInfo installerInfo = snapshot.getApplicationInfo(
@@ -476,6 +477,14 @@ public class PackageArchiver {
}
}
+ private void verifyInstalled(PackageStateInternal ps, int userId)
+ throws PackageManager.NameNotFoundException {
+ if (!ps.getUserStateOrDefault(userId).isInstalled()) {
+ throw new PackageManager.NameNotFoundException(
+ TextUtils.formatSimple("%s is not installed.", ps.getPackageName()));
+ }
+ }
+
/**
* Returns true if the app is archivable.
*/
@@ -519,11 +528,11 @@ public class PackageArchiver {
/**
* Returns true if user has opted the app out of archiving through system settings.
*/
- // TODO(b/304256918) Switch this to a separate OP code for archiving.
private boolean isAppOptedOutOfArchiving(String packageName, int uid) {
return Binder.withCleanCallingIdentity(() ->
- getAppOpsManager().checkOp(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
- uid, packageName) == MODE_IGNORED);
+ getAppOpsManager().checkOpNoThrow(
+ AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, uid, packageName)
+ == MODE_IGNORED);
}
private void verifyOptOutStatus(String packageName, int uid)
@@ -676,23 +685,51 @@ public class PackageArchiver {
PackageStateInternal ps;
try {
ps = getPackageState(packageName, snapshot, callingUid, userId);
- snapshot.enforceCrossUserPermission(callingUid, userId, true, false,
- "getArchivedAppIcon");
- verifyArchived(ps, userId);
} catch (PackageManager.NameNotFoundException e) {
- throw new ParcelableException(e);
+ Slog.e(TAG, TextUtils.formatSimple("Package %s couldn't be found.", packageName), e);
+ return null;
}
- List<ArchiveActivityInfo> activityInfos = ps.getUserStateOrDefault(
- userId).getArchiveState().getActivityInfos();
- if (activityInfos.size() == 0) {
+ ArchiveState archiveState = getAnyArchiveState(ps, userId);
+ if (archiveState == null || archiveState.getActivityInfos().size() == 0) {
return null;
}
// TODO(b/298452477) Handle monochrome icons.
// In the rare case the archived app defined more than two launcher activities, we choose
// the first one arbitrarily.
- return includeCloudOverlay(decodeIcon(activityInfos.get(0)));
+ return includeCloudOverlay(decodeIcon(archiveState.getActivityInfos().get(0)));
+ }
+
+ /**
+ * This method first checks the ArchiveState for the provided userId and then tries to fallback
+ * to other users if the current user is not archived.
+ *
+ * <p> This fallback behaviour is required for archived apps to fit into the multi-user world
+ * where APKs are shared across users. E.g. current ways of fetching icons for apps that are
+ * only installed on the work profile also work when executed on the personal profile if you're
+ * using {@link PackageManager#MATCH_UNINSTALLED_PACKAGES}. Resource fetching from APKs is for
+ * the most part userId-agnostic, which we need to mimic here in order for existing methods
+ * like {@link PackageManager#getApplicationIcon} to continue working.
+ *
+ * @return {@link ArchiveState} for {@code userId} if present. If not present, false back to an
+ * arbitrary userId. If no user is archived, returns null.
+ */
+ @Nullable
+ private ArchiveState getAnyArchiveState(PackageStateInternal ps, int userId) {
+ PackageUserStateInternal userState = ps.getUserStateOrDefault(userId);
+ if (isArchived(userState)) {
+ return userState.getArchiveState();
+ }
+
+ for (int i = 0; i < ps.getUserStates().size(); i++) {
+ userState = ps.getUserStates().valueAt(i);
+ if (isArchived(userState)) {
+ return userState.getArchiveState();
+ }
+ }
+
+ return null;
}
@VisibleForTesting
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/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 47d1df5df1c0..4adb60c34c52 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -168,6 +168,7 @@ import com.android.internal.content.InstallLocationUtils;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.os.SomeArgs;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.security.VerityUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -181,7 +182,6 @@ import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 1e7d0437d99e..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
@@ -762,13 +767,14 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
}
@Override
- public boolean isPackageQuarantined(@NonNull String packageName,
- @UserIdInt int userId) {
+ public boolean isPackageQuarantined(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException {
return snapshot().isPackageQuarantinedForUser(packageName, userId);
}
@Override
- public boolean isPackageStopped(@NonNull String packageName, @UserIdInt int userId) {
+ public boolean isPackageStopped(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException {
return snapshot().isPackageStoppedForUser(packageName, userId);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c5b006c4c77d..bc441b84c58b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -185,6 +185,7 @@ import com.android.internal.pm.parsing.pkg.AndroidPackageInternal;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -238,7 +239,6 @@ import com.android.server.pm.pkg.SharedUserApi;
import com.android.server.pm.pkg.mutate.PackageStateMutator;
import com.android.server.pm.pkg.mutate.PackageStateWrite;
import com.android.server.pm.pkg.mutate.PackageUserStateWrite;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.resolution.ComponentResolver;
import com.android.server.pm.resolution.ComponentResolverApi;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
@@ -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.
@@ -2013,6 +2014,16 @@ public class PackageManagerService implements PackageSender, TestUtilityService
public boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ }
};
// CHECKSTYLE:ON IndentationCheck
@@ -3127,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
@@ -3135,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;
}
@@ -3158,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) {
@@ -5242,14 +5256,19 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String getSuspendingPackage(String packageName, int userId) {
- final int callingUid = Binder.getCallingUid();
- final Computer snapshot = snapshot();
- // This will do visibility checks as well.
- if (!snapshot.isPackageSuspendedForUser(packageName, userId)) {
+ try {
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshot();
+ // This will do visibility checks as well.
+ if (!snapshot.isPackageSuspendedForUser(packageName, userId)) {
+ return null;
+ }
+ final UserPackage suspender = mSuspendPackageHelper.getSuspendingPackage(
+ snapshot, packageName, userId, callingUid);
+ return suspender != null ? suspender.packageName : null;
+ } catch (PackageManager.NameNotFoundException e) {
return null;
}
- return mSuspendPackageHelper.getSuspendingPackage(snapshot, packageName, userId,
- callingUid);
}
@Override
@@ -6184,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()) {
@@ -6193,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);
}
@@ -6639,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);
}
@@ -6653,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 bb0017c80d6d..b6de0e5c030f 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -20,19 +20,23 @@ 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;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedLongSparseArray;
import java.util.ArrayList;
@@ -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 109d7ba1d29e..f42b43f5aeef 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -44,12 +44,12 @@ import android.util.Slog;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.parsing.PackageCacher;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -167,7 +167,7 @@ final class RemovePackageHelper {
if (removedPackage != null) {
// TODO: Use PackageState for isSystem
cleanPackageDataStructuresLILPw(removedPackage,
- AndroidPackageUtils.isSystem(removedPackage), chatty);
+ AndroidPackageLegacyUtils.isSystem(removedPackage), chatty);
}
}
}
@@ -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/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 31a63e07b66c..5c6d61e3eaf9 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -74,11 +74,13 @@ import android.util.jar.StrictJarFile;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.PackageInfoUtils;
@@ -86,8 +88,6 @@ import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateUtils;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedArraySet;
import dalvik.system.VMRuntime;
diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java
index 37cf30bd63fe..41e2a3f3d318 100644
--- a/services/core/java/com/android/server/pm/ScanRequest.java
+++ b/services/core/java/com/android/server/pm/ScanRequest.java
@@ -22,8 +22,8 @@ import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
/** A package to be scanned */
@VisibleForTesting
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 75d88da059b5..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;
@@ -89,6 +90,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
@@ -106,7 +108,6 @@ import com.android.server.LocalServices;
import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.permission.LegacyPermissionSettings;
import com.android.server.pm.permission.LegacyPermissionState;
@@ -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/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index dddc6b0fbb7a..5c0a15a28285 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -25,14 +25,14 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedProcess;
+import com.android.internal.pm.pkg.component.ParsedProcessImpl;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedProcessImpl;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchedArraySet;
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index b607502baada..7d87d1b27da0 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -47,11 +47,11 @@ import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.policy.AttributeCache;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index fe8c12c8e232..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,12 +422,25 @@ public final class SuspendPackageHelper {
return null;
}
- String suspendingPackage = null;
+ UserPackage suspendingPackage = null;
+ UserPackage suspendedBySystem = null;
+ UserPackage qasPackage = null;
for (int i = 0; i < userState.getSuspendParams().size(); i++) {
suspendingPackage = userState.getSuspendParams().keyAt(i);
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
- return suspendingPackage;
+ var suspendParams = userState.getSuspendParams().valueAt(i);
+ if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage.packageName)) {
+ suspendedBySystem = suspendingPackage;
}
+ if (suspendParams.isQuarantined() && qasPackage == null) {
+ qasPackage = suspendingPackage;
+ }
+ }
+ // Precedence: quarantined, then system, then suspending.
+ if (qasPackage != null) {
+ return qasPackage;
+ }
+ if (suspendedBySystem != null) {
+ return suspendedBySystem;
}
return suspendingPackage;
}
@@ -438,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);
@@ -451,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;
@@ -480,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;
@@ -542,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;
@@ -559,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
@@ -601,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 =
@@ -622,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/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a7b52f4e7a58..c48eccf2aac5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -532,9 +532,10 @@ public class UserManagerService extends IUserManager.Stub {
}
final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT, android.content.IntentSender.class);
final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
+ final String callingPackage = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
// Call setQuietModeEnabled on bg thread to avoid ANR
BackgroundThread.getHandler().post(() ->
- setQuietModeEnabled(userId, false, target, /* callingPackage */ null));
+ setQuietModeEnabled(userId, false, target, callingPackage));
}
};
@@ -1410,7 +1411,7 @@ public class UserManagerService extends IUserManager.Stub {
if (onlyIfCredentialNotRequired) {
return false;
}
- showConfirmCredentialToDisableQuietMode(userId, target);
+ showConfirmCredentialToDisableQuietMode(userId, target, callingPackage);
return false;
}
}
@@ -1434,7 +1435,7 @@ public class UserManagerService extends IUserManager.Stub {
if (onlyIfCredentialNotRequired) {
return false;
}
- showConfirmCredentialToDisableQuietMode(userId, target);
+ showConfirmCredentialToDisableQuietMode(userId, target, callingPackage);
return false;
}
setQuietModeEnabled(userId, false /* enableQuietMode */, target, callingPackage);
@@ -1604,7 +1605,7 @@ public class UserManagerService extends IUserManager.Stub {
* Show confirm credential screen to unlock user in order to turn off quiet mode.
*/
private void showConfirmCredentialToDisableQuietMode(
- @UserIdInt int userId, @Nullable IntentSender target) {
+ @UserIdInt int userId, @Nullable IntentSender target, @Nullable String callingPackage) {
if (android.app.admin.flags.Flags.quietModeCredentialBugFix()) {
// TODO (b/308121702) It may be brittle to rely on user states to check profile state
int state;
@@ -1635,6 +1636,7 @@ public class UserManagerService extends IUserManager.Stub {
}
callBackIntent.putExtra(Intent.EXTRA_USER_ID, userId);
callBackIntent.setPackage(mContext.getPackageName());
+ callBackIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackage);
callBackIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
mContext,
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/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
index 459e2cf7f5c0..79c9c8ec8b0b 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageCacher.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -28,9 +28,9 @@ import android.system.StructStat;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.ApexManager;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import libcore.io.IoUtils;
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 b23dbee5e973..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;
@@ -52,6 +53,9 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
+import com.android.internal.pm.pkg.component.ComponentParseUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedAttribution;
import com.android.internal.pm.pkg.component.ParsedComponent;
@@ -63,11 +67,12 @@ import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
import com.android.server.pm.PackageArchiver;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageStateUnserialized;
@@ -75,9 +80,6 @@ import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.PackageUserStateUtils;
import com.android.server.pm.pkg.SELinuxUtil;
-import com.android.server.pm.pkg.component.ComponentParseUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.io.File;
import java.util.ArrayList;
@@ -273,8 +275,8 @@ public class PackageInfoUtils {
final ActivityInfo[] res = new ActivityInfo[N];
for (int i = 0; i < N; i++) {
final ParsedActivity a = pkg.getActivities().get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), a,
- aflags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ a.isEnabled(), a.isDirectBootAware(), a.getName(), aflags)) {
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
a.getName())) {
continue;
@@ -293,8 +295,8 @@ public class PackageInfoUtils {
final ActivityInfo[] res = new ActivityInfo[size];
for (int i = 0; i < size; i++) {
final ParsedActivity a = pkg.getReceivers().get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), a,
- flags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ a.isEnabled(), a.isDirectBootAware(), a.getName(), flags)) {
res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
userId, pkgSetting);
}
@@ -309,8 +311,8 @@ public class PackageInfoUtils {
final ServiceInfo[] res = new ServiceInfo[size];
for (int i = 0; i < size; i++) {
final ParsedService s = pkg.getServices().get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), s,
- flags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ s.isEnabled(), s.isDirectBootAware(), s.getName(), flags)) {
res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
userId, pkgSetting);
}
@@ -326,8 +328,8 @@ public class PackageInfoUtils {
for (int i = 0; i < size; i++) {
final ParsedProvider pr = pkg.getProviders()
.get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), pr,
- flags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ pr.isEnabled(), pr.isDirectBootAware(), pr.getName(), flags)) {
res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo,
userId, pkgSetting);
}
@@ -473,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();
}
@@ -923,7 +952,7 @@ public class PackageInfoUtils {
| flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
| flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
| flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
- | flag(AndroidPackageUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
+ | flag(AndroidPackageLegacyUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
| flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST);
return appInfoFlags(pkgWithoutStateFlags, pkgSetting);
@@ -964,12 +993,12 @@ public class PackageInfoUtils {
| flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
| flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
| flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING)
- | flag(AndroidPackageUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
- | flag(AndroidPackageUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
- | flag(AndroidPackageUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM)
- | flag(AndroidPackageUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR)
- | flag(AndroidPackageUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
- | flag(AndroidPackageUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM)
+ | flag(AndroidPackageLegacyUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
+ | flag(AndroidPackageLegacyUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ | flag(AndroidPackageLegacyUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM)
+ | flag(AndroidPackageLegacyUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR)
+ | flag(AndroidPackageLegacyUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
+ | flag(AndroidPackageLegacyUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM)
| flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
Boolean resizeableActivity = pkg.getResizeableActivity();
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index 1c751e07bbbe..b6a08a5a546f 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -35,17 +35,19 @@ import android.util.DisplayMetrics;
import android.util.Slog;
import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
import com.android.server.pm.PackageManagerException;
import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.io.File;
import java.util.List;
+import java.util.Set;
/**
* The v2 of package parsing for use when parsing is initiated in the server and must
@@ -88,6 +90,16 @@ public class PackageParser2 implements AutoCloseable {
// behavior.
return false;
}
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ }
});
}
@@ -221,7 +233,7 @@ public class PackageParser2 implements AutoCloseable {
@NonNull String baseCodePath, @NonNull String codePath,
@NonNull TypedArray manifestArray, boolean isCoreApp) {
return PackageImpl.forParsing(packageName, baseCodePath, codePath, manifestArray,
- isCoreApp);
+ isCoreApp, Callback.this);
}
/**
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 61be6e1036f2..1b7c7ad94dc9 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -29,7 +29,9 @@ import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.incremental.IncrementalManager;
import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.pm.parsing.PackageParserException;
import com.android.internal.pm.parsing.pkg.AndroidPackageHidden;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedProvider;
@@ -37,7 +39,6 @@ import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
-import com.android.server.pm.PackageManagerException;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -134,10 +135,10 @@ public class AndroidPackageUtils {
/**
* Validate the dex metadata files installed for the given package.
*
- * @throws PackageManagerException in case of errors.
+ * @throws PackageParserException in case of errors.
*/
public static void validatePackageDexMetadata(AndroidPackage pkg)
- throws PackageManagerException {
+ throws PackageParserException {
Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
String packageName = pkg.getPackageName();
long versionCode = pkg.getLongVersionCode();
@@ -146,7 +147,7 @@ public class AndroidPackageUtils {
final ParseResult result = DexMetadataHelper.validateDexMetadataFile(
input.reset(), dexMetadata, packageName, versionCode);
if (result.isError()) {
- throw new PackageManagerException(
+ throw new PackageParserException(
result.getErrorCode(), result.getErrorMessage(), result.getException());
}
}
@@ -314,60 +315,4 @@ public class AndroidPackageUtils {
info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode();
info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
}
-
- /**
- * @deprecated Use {@link PackageState#isSystem}
- */
- @Deprecated
- public static boolean isSystem(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isSystem();
- }
-
- /**
- * @deprecated Use {@link PackageState#isSystemExt}
- */
- @Deprecated
- public static boolean isSystemExt(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isSystemExt();
- }
-
- /**
- * @deprecated Use {@link PackageState#isPrivileged}
- */
- @Deprecated
- public static boolean isPrivileged(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isPrivileged();
- }
-
- /**
- * @deprecated Use {@link PackageState#isOem}
- */
- @Deprecated
- public static boolean isOem(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isOem();
- }
-
- /**
- * @deprecated Use {@link PackageState#isVendor}
- */
- @Deprecated
- public static boolean isVendor(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isVendor();
- }
-
- /**
- * @deprecated Use {@link PackageState#isProduct}
- */
- @Deprecated
- public static boolean isProduct(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isProduct();
- }
-
- /**
- * @deprecated Use {@link PackageState#isOdm}
- */
- @Deprecated
- public static boolean isOdm(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isOdm();
- }
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 8bd2d94667f9..671e031b546b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -120,8 +120,11 @@ import com.android.internal.compat.IPlatformCompat;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.RoSystemProperties;
+import com.android.internal.pm.permission.CompatibilityPermissionInfo;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.IntPair;
@@ -144,8 +147,6 @@ import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.SoftRestrictedPermissionPolicy;
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/SELinuxUtil.java b/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
index 6cbc1de75010..6a156415982c 100644
--- a/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
+++ b/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
@@ -16,6 +16,8 @@
package com.android.server.pm.pkg;
+import com.android.internal.pm.pkg.SEInfoUtil;
+
/**
* Utility methods that need to be used in application space.
* @hide
@@ -23,10 +25,10 @@ package com.android.server.pm.pkg;
public final class SELinuxUtil {
/** Append to existing seinfo label for instant apps @hide */
- private static final String INSTANT_APP_STR = ":ephemeralapp";
+ private static final String INSTANT_APP_STR = SEInfoUtil.INSTANT_APP_STR;
/** Append to existing seinfo when modifications are complete @hide */
- public static final String COMPLETE_STR = ":complete";
+ public static final String COMPLETE_STR = SEInfoUtil.COMPLETE_STR;
/** @hide */
public static String getSeinfoUser(PackageUserState userState) {
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/pm/resolution/ComponentResolver.java b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
index 532a7f8f893f..c9da99da7902 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
@@ -45,11 +45,13 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.util.ArrayUtils;
import com.android.server.IntentResolver;
@@ -62,8 +64,6 @@ import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageStateUtils;
import com.android.server.pm.pkg.PackageUserStateInternal;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
import com.android.server.pm.snapshot.PackageDataSnapshot;
import com.android.server.utils.Snappable;
import com.android.server.utils.SnapshotCache;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4e5dc1dd76fa..938ed2329ffd 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -76,7 +76,6 @@ import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
import static android.view.contentprotection.flags.Flags.createAccessibilityOverlayAppOpEnabled;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
-import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -97,7 +96,6 @@ import static com.android.server.wm.WindowManagerPolicyProto.SCREEN_ON_FULLY;
import static com.android.server.wm.WindowManagerPolicyProto.WINDOW_MANAGER_DRAW_COMPLETE;
import android.accessibilityservice.AccessibilityService;
-import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -124,7 +122,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -204,8 +201,6 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
-import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
-import com.android.internal.accessibility.util.AccessibilityUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.internal.display.BrightnessUtils;
@@ -385,8 +380,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public static final String TRACE_WAIT_FOR_ALL_WINDOWS_DRAWN_METHOD = "waitForAllWindowsDrawn";
- private static final String TALKBACK_LABEL = "TalkBack";
-
private static final int POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS = 800;
/**
@@ -477,6 +470,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** Controller that supports enabling an AccessibilityService by holding down the volume keys */
private AccessibilityShortcutController mAccessibilityShortcutController;
+ private TalkbackShortcutController mTalkbackShortcutController;
+
boolean mSafeMode;
// Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
@@ -813,7 +808,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
handleScreenShot(msg.arg1);
break;
case MSG_SWITCH_KEYBOARD_LAYOUT:
- handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
+ SwitchKeyboardLayoutMessageObject object =
+ (SwitchKeyboardLayoutMessageObject) msg.obj;
+ handleSwitchKeyboardLayout(object.keyEvent, object.direction,
+ object.focusedToken);
break;
case MSG_LOG_KEYBOARD_SYSTEM_EVENT:
handleKeyboardSystemEvent(KeyboardLogEvent.from(msg.arg1), (KeyEvent) msg.obj);
@@ -934,6 +932,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ private record SwitchKeyboardLayoutMessageObject(KeyEvent keyEvent, IBinder focusedToken,
+ int direction) {
+ }
+
final IPersistentVrStateCallbacks mPersistentVrModeListener =
new IPersistentVrStateCallbacks.Stub() {
@Override
@@ -1602,19 +1604,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (DEBUG_INPUT) {
Slog.d(TAG, "Executing stem primary triple press action behavior.");
}
-
- if (Settings.System.getIntForUser(mContext.getContentResolver(),
- Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED,
- /* def= */ 0, UserHandle.USER_CURRENT) == 1) {
- /** Toggle talkback begin */
- ComponentName componentName = getTalkbackComponent();
- if (componentName != null && toggleTalkBack(componentName)) {
- /** log stem triple press telemetry if it's a talkback enabled event */
- logStemTriplePressAccessibilityTelemetry(componentName);
- }
- performHapticFeedback(HapticFeedbackConstants.CONFIRM, /* always = */ false,
- /* reason = */ "Stem primary - Triple Press - Toggle Accessibility");
- /** Toggle talkback end */
+ mTalkbackShortcutController.toggleTalkback(mCurrentUserId);
+ if (mTalkbackShortcutController.isTalkBackShortcutGestureEnabled()) {
+ performHapticFeedback(HapticFeedbackConstants.CONFIRM, /* always = */
+ false, /* reason = */
+ "Stem primary - Triple Press - Toggle Accessibility");
}
break;
}
@@ -1640,61 +1634,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/**
- * A function that toggles talkback service
- *
- * @return {@code true} if talkback is enabled, {@code false} if talkback is disabled
- */
- private boolean toggleTalkBack(ComponentName componentName) {
- final Set<ComponentName> enabledServices =
- AccessibilityUtils.getEnabledServicesFromSettings(mContext, mCurrentUserId);
-
- boolean isTalkbackAlreadyEnabled = enabledServices.contains(componentName);
- AccessibilityUtils.setAccessibilityServiceState(mContext, componentName,
- !isTalkbackAlreadyEnabled);
- /** if isTalkbackAlreadyEnabled is true, then it's a disabled event so return false
- * and if isTalkbackAlreadyEnabled is false, return true as it's an enabled event */
- return !isTalkbackAlreadyEnabled;
- }
-
- /**
- * A function that logs stem triple press accessibility telemetry
- * If the user setup (Oobe) is not completed, set the
- * WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE
- * setting which will be later logged via Settings Snapshot
- * else, log ACCESSIBILITY_SHORTCUT_REPORTED atom
- */
- private void logStemTriplePressAccessibilityTelemetry(ComponentName componentName) {
- if (!AccessibilityUtils.isUserSetupCompleted(mContext)) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE, 1);
- } else {
- AccessibilityStatsLogUtils.logAccessibilityShortcutActivated(mContext, componentName,
- ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE,
- /* serviceEnabled= */ true);
- }
- }
-
- private ComponentName getTalkbackComponent() {
- AccessibilityManager accessibilityManager = mContext.getSystemService(
- AccessibilityManager.class);
- List<AccessibilityServiceInfo> serviceInfos =
- accessibilityManager.getInstalledAccessibilityServiceList();
-
- for (AccessibilityServiceInfo service : serviceInfos) {
- final ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
- if (isTalkback(serviceInfo)) {
- return new ComponentName(serviceInfo.packageName, serviceInfo.name);
- }
- }
- return null;
- }
-
- private boolean isTalkback(ServiceInfo info) {
- String label = info.loadLabel(mPackageManager).toString();
- return label.equals(TALKBACK_LABEL);
- }
-
- /**
* Load most recent task (expect current task) and bring it to the front.
*/
void performStemPrimaryDoublePressSwitchToRecentTask() {
@@ -1731,12 +1670,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case TRIPLE_PRESS_PRIMARY_NOTHING:
break;
case TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY:
- if (Settings.System.getIntForUser(
- mContext.getContentResolver(),
- Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED,
- /* def= */ 0,
- UserHandle.USER_CURRENT)
- == 1) {
+ if (mTalkbackShortcutController.isTalkBackShortcutGestureEnabled()) {
return 3;
}
break;
@@ -2252,6 +2186,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
ButtonOverridePermissionChecker getButtonOverridePermissionChecker() {
return new ButtonOverridePermissionChecker();
}
+
+ TalkbackShortcutController getTalkbackShortcutController() {
+ return new TalkbackShortcutController(mContext);
+ }
}
/** {@inheritDoc} */
@@ -2515,6 +2453,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardDrawnTimeout = mContext.getResources().getInteger(
com.android.internal.R.integer.config_keyguardDrawnTimeout);
mKeyguardDelegate = injector.getKeyguardServiceDelegate();
+ mTalkbackShortcutController = injector.getTalkbackShortcutController();
initKeyCombinationRules();
initSingleKeyGestureRules(injector.getLooper());
mButtonOverridePermissionChecker = injector.getButtonOverridePermissionChecker();
@@ -3709,7 +3648,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_LANGUAGE_SWITCH:
if (firstDown) {
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
- sendSwitchKeyboardLayout(event, direction);
+ sendSwitchKeyboardLayout(event, focusedToken, direction);
logKeyboardSystemsEvent(event, KeyboardLogEvent.LANGUAGE_SWITCH);
return true;
}
@@ -3978,7 +3917,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
+ ", policyFlags=" + policyFlags);
}
- if (interceptUnhandledKey(event)) {
+ if (interceptUnhandledKey(event, focusedToken)) {
return null;
}
@@ -4036,7 +3975,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return fallbackEvent;
}
- private boolean interceptUnhandledKey(KeyEvent event) {
+ private boolean interceptUnhandledKey(KeyEvent event, IBinder focusedToken) {
final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
@@ -4049,7 +3988,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (KeyEvent.metaStateHasModifiers(metaState & ~KeyEvent.META_SHIFT_MASK,
KeyEvent.META_CTRL_ON)) {
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
- sendSwitchKeyboardLayout(event, direction);
+ sendSwitchKeyboardLayout(event, focusedToken, direction);
return true;
}
}
@@ -4105,16 +4044,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- private void sendSwitchKeyboardLayout(@NonNull KeyEvent event, int direction) {
- mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, event.getDeviceId(),
- direction).sendToTarget();
+ private void sendSwitchKeyboardLayout(@NonNull KeyEvent event,
+ @Nullable IBinder focusedToken, int direction) {
+ SwitchKeyboardLayoutMessageObject object =
+ new SwitchKeyboardLayoutMessageObject(event, focusedToken, direction);
+ mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, object).sendToTarget();
}
- private void handleSwitchKeyboardLayout(int deviceId, int direction) {
+ private void handleSwitchKeyboardLayout(@NonNull KeyEvent event, int direction,
+ IBinder focusedToken) {
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)) {
- InputMethodManagerInternal.get().switchKeyboardLayout(direction);
+ IBinder targetWindowToken =
+ mWindowManagerInternal.getTargetWindowTokenFromInputToken(focusedToken);
+ InputMethodManagerInternal.get().onSwitchKeyboardLayoutShortcut(direction,
+ event.getDisplayId(), targetWindowToken);
} else {
- mWindowManagerFuncs.switchKeyboardLayout(deviceId, direction);
+ mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
}
}
@@ -4124,7 +4069,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if ((actions & ACTION_PASS_TO_USER) != 0) {
long delayMillis = interceptKeyBeforeDispatching(
focusedToken, fallbackEvent, policyFlags);
- if (delayMillis == 0 && !interceptUnhandledKey(fallbackEvent)) {
+ if (delayMillis == 0 && !interceptUnhandledKey(fallbackEvent, focusedToken)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/policy/TalkbackShortcutController.java b/services/core/java/com/android/server/policy/TalkbackShortcutController.java
new file mode 100644
index 000000000000..906da2f4cdf5
--- /dev/null
+++ b/services/core/java/com/android/server/policy/TalkbackShortcutController.java
@@ -0,0 +1,118 @@
+/*
+ * 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.policy;
+
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
+import com.android.internal.accessibility.util.AccessibilityUtils;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class controls talkback shortcut related operations such as toggling, quering and
+ * logging.
+ */
+@VisibleForTesting
+class TalkbackShortcutController {
+ private static final String TALKBACK_LABEL = "TalkBack";
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+
+ TalkbackShortcutController(Context context) {
+ mContext = context;
+ mPackageManager = mContext.getPackageManager();
+ }
+
+ /**
+ * A function that toggles talkback service.
+ *
+ * @return talkback state after toggle. {@code true} if talkback is enabled, {@code false} if
+ * talkback is disabled
+ */
+ boolean toggleTalkback(int userId) {
+ final Set<ComponentName> enabledServices =
+ AccessibilityUtils.getEnabledServicesFromSettings(mContext, userId);
+ ComponentName componentName = getTalkbackComponent();
+ boolean isTalkbackAlreadyEnabled = enabledServices.contains(componentName);
+
+ if (isTalkBackShortcutGestureEnabled()) {
+ isTalkbackAlreadyEnabled = !isTalkbackAlreadyEnabled;
+ AccessibilityUtils.setAccessibilityServiceState(mContext, componentName,
+ isTalkbackAlreadyEnabled);
+
+ // log stem triple press telemetry if it's a talkback enabled event.
+ if (componentName != null && isTalkbackAlreadyEnabled) {
+ logStemTriplePressAccessibilityTelemetry(componentName);
+ }
+ }
+ return isTalkbackAlreadyEnabled;
+ }
+
+ private ComponentName getTalkbackComponent() {
+ AccessibilityManager accessibilityManager = mContext.getSystemService(
+ AccessibilityManager.class);
+ List<AccessibilityServiceInfo> serviceInfos =
+ accessibilityManager.getInstalledAccessibilityServiceList();
+
+ for (AccessibilityServiceInfo service : serviceInfos) {
+ final ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
+ if (isTalkback(serviceInfo)) {
+ return new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ }
+ }
+ return null;
+ }
+
+ boolean isTalkBackShortcutGestureEnabled() {
+ return Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED,
+ /* def= */ 0, UserHandle.USER_CURRENT) == 1;
+ }
+
+ /**
+ * A function that logs stem triple press accessibility telemetry. If the user setup (Oobe)
+ * is not completed, set the WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE setting which
+ * will be later logged via Settings Snapshot else, log ACCESSIBILITY_SHORTCUT_REPORTED atom
+ */
+ private void logStemTriplePressAccessibilityTelemetry(ComponentName componentName) {
+ if (!AccessibilityUtils.isUserSetupCompleted(mContext)) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE, 1);
+ return;
+ }
+ AccessibilityStatsLogUtils.logAccessibilityShortcutActivated(mContext,
+ componentName,
+ ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE,
+ /* serviceEnabled= */ true);
+ }
+
+ private boolean isTalkback(ServiceInfo info) {
+ return TALKBACK_LABEL.equals(info.loadLabel(mPackageManager).toString());
+ }
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index eac4fc00b667..9a85c42e1a10 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1608,14 +1608,12 @@ public class TrustManagerService extends SystemService {
user.name, user.id, user.flags);
if (!user.supportsSwitchToByUser()) {
final boolean locked;
- if (user.isProfile()) {
- if (mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id)) {
- fout.print(" (profile with separate challenge)");
- locked = isDeviceLockedInner(user.id);
- } else {
- fout.print(" (profile with unified challenge)");
- locked = isDeviceLockedInner(resolveProfileParent(user.id));
- }
+ if (mLockPatternUtils.isProfileWithUnifiedChallenge(user.id)) {
+ fout.print(" (profile with unified challenge)");
+ locked = isDeviceLockedInner(resolveProfileParent(user.id));
+ } else if (mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id)) {
+ fout.print(" (profile with separate challenge)");
+ locked = isDeviceLockedInner(user.id);
} else {
fout.println(" (user that cannot be switched to)");
locked = isDeviceLockedInner(user.id);
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/ActivityMetricsLaunchObserver.java b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
index 81e5fbd564e0..769f01c34e17 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
@@ -142,8 +142,11 @@ public class ActivityMetricsLaunchObserver {
* if the launching activity is started from an existing launch sequence (trampoline)
* but cannot coalesce to the existing one, e.g. to a different display.
* @param name The launching activity name.
+ * @param temperature The temperature at which a launch sequence had started.
+ * @param userId The id of the user the activity is being launched for.
*/
- public void onActivityLaunched(long id, ComponentName name, @Temperature int temperature) {
+ public void onActivityLaunched(long id, ComponentName name, @Temperature int temperature,
+ int userId) {
}
/**
@@ -177,13 +180,15 @@ public class ActivityMetricsLaunchObserver {
* @param timestampNanos the timestamp of ActivityLaunchFinished event in nanoseconds.
* To compute the TotalTime duration, deduct the timestamp {@link #onIntentStarted}
* from {@code timestampNanos}.
+ * @param launchMode The activity launch mode.
*
* @apiNote The finishing activity isn't necessarily the same as the starting activity;
* in the case of a trampoline, multiple activities could've been started
* and only the latest activity that was top-most during first-frame drawn
* is reported here.
*/
- public void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos) {
+ public void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos,
+ int launchMode) {
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 7b20529ce5e1..78f501ad9fed 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -1737,7 +1737,8 @@ class ActivityMetricsLogger {
// Beginning a launch is timing sensitive and so should be observed as soon as possible.
mLaunchObserver.onActivityLaunched(info.mLaunchingState.mStartUptimeNs,
- info.mLastLaunchedActivity.mActivityComponent, temperature);
+ info.mLastLaunchedActivity.mActivityComponent, temperature,
+ info.mLastLaunchedActivity.mUserId);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -1774,7 +1775,8 @@ class ActivityMetricsLogger {
"MetricsLogger:launchObserverNotifyActivityLaunchFinished");
mLaunchObserver.onActivityLaunchFinished(info.mLaunchingState.mStartUptimeNs,
- info.mLastLaunchedActivity.mActivityComponent, timestampNs);
+ info.mLastLaunchedActivity.mActivityComponent, timestampNs,
+ info.mLastLaunchedActivity.launchMode);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
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/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 73edb4bed6ca..869bcc0f9b8f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1053,6 +1053,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mWindowManager = wm;
mRootWindowContainer = wm.mRoot;
mWindowOrganizerController.mTransitionController.setWindowManager(wm);
+ mLifecycleManager.setWindowManager(wm);
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
mConfigurationSeq = mTempConfig.seq = 1;
@@ -1274,7 +1275,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
-
final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);
assertPackageMatchesCallingUid(callingPackage);
@@ -1315,7 +1315,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
.setActivityOptions(opts)
.setUserId(userId)
.execute();
-
}
@Override
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 92665af1075b..4929df8061b2 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static android.os.Process.SYSTEM_UID;
import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER;
@@ -49,7 +50,6 @@ import android.compat.annotation.EnabledAfter;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
import android.provider.DeviceConfig;
@@ -86,7 +86,7 @@ public class BackgroundActivityStartController {
private static final int NO_PROCESS_UID = -1;
/** If enabled the creator will not allow BAL on its behalf by default. */
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @EnabledAfter(targetSdkVersion = UPSIDE_DOWN_CAKE)
private static final long DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_CREATOR =
296478951;
public static final ActivityOptions ACTIVITY_OPTIONS_SYSTEM_DEFINED =
@@ -228,6 +228,7 @@ public class BackgroundActivityStartController {
private final Intent mIntent;
private final WindowProcessController mCallerApp;
private final WindowProcessController mRealCallerApp;
+ private final boolean mIsCallForResult;
private BalState(int callingUid, int callingPid, final String callingPackage,
int realCallingUid, int realCallingPid,
@@ -247,8 +248,10 @@ public class BackgroundActivityStartController {
mOriginatingPendingIntent = originatingPendingIntent;
mIntent = intent;
mRealCallingPackage = mService.getPackageNameIfUnique(realCallingUid, realCallingPid);
- if (originatingPendingIntent == null // not a PendingIntent
- || resultRecord != null // sent for result
+ mIsCallForResult = resultRecord != null;
+ if (balRequireOptInByPendingIntentCreator() // auto-opt in introduced with this feature
+ && (originatingPendingIntent == null // not a PendingIntent
+ || mIsCallForResult) // sent for result
) {
// grant BAL privileges unless explicitly opted out
mBalAllowedByPiCreatorWithHardening = mBalAllowedByPiCreator =
@@ -351,6 +354,19 @@ public class BackgroundActivityStartController {
return name + "[debugOnly]";
}
+ /** @return valid targetSdk or <code>-1</code> */
+ private int getTargetSdk(String packageName) {
+ if (packageName == null) {
+ return -1;
+ }
+ try {
+ PackageManager pm = mService.mContext.getPackageManager();
+ return pm.getTargetSdkVersion(packageName);
+ } catch (Exception e) {
+ return -1;
+ }
+ }
+
private boolean hasRealCaller() {
return mRealCallingUid != NO_PROCESS_UID;
}
@@ -368,6 +384,7 @@ public class BackgroundActivityStartController {
StringBuilder sb = new StringBuilder(2048);
sb.append("[callingPackage: ")
.append(getDebugPackageName(mCallingPackage, mCallingUid));
+ sb.append("; callingPackageTargetSdk: ").append(getTargetSdk(mCallingPackage));
sb.append("; callingUid: ").append(mCallingUid);
sb.append("; callingPid: ").append(mCallingPid);
sb.append("; appSwitchState: ").append(mAppSwitchState);
@@ -387,10 +404,13 @@ public class BackgroundActivityStartController {
.append(mBalAllowedByPiCreatorWithHardening);
sb.append("; resultIfPiCreatorAllowsBal: ").append(resultIfPiCreatorAllowsBal);
sb.append("; hasRealCaller: ").append(hasRealCaller());
+ sb.append("; isCallForResult: ").append(mIsCallForResult);
sb.append("; isPendingIntent: ").append(isPendingIntent());
if (hasRealCaller()) {
sb.append("; realCallingPackage: ")
.append(getDebugPackageName(mRealCallingPackage, mRealCallingUid));
+ sb.append("; realCallingPackageTargetSdk: ")
+ .append(getTargetSdk(mRealCallingPackage));
sb.append("; realCallingUid: ").append(mRealCallingUid);
sb.append("; realCallingPid: ").append(mRealCallingPid);
sb.append("; realCallingUidHasAnyVisibleWindow: ")
diff --git a/services/core/java/com/android/server/wm/ClientLifecycleManager.java b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
index 8b282dd3e7a8..6b6388b10ce7 100644
--- a/services/core/java/com/android/server/wm/ClientLifecycleManager.java
+++ b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
@@ -22,7 +22,13 @@ import android.app.servertransaction.ActivityLifecycleItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
/**
* Class that is able to combine multiple client lifecycle transition requests and/or callbacks,
@@ -31,8 +37,18 @@ import android.os.RemoteException;
* @see ClientTransaction
*/
class ClientLifecycleManager {
- // TODO(lifecycler): Implement building transactions or global transaction.
- // TODO(lifecycler): Use object pools for transactions and transaction items.
+
+ private static final String TAG = "ClientLifecycleManager";
+
+ /** Mapping from client process binder to its pending transaction. */
+ @VisibleForTesting
+ final ArrayMap<IBinder, ClientTransaction> mPendingTransactions = new ArrayMap<>();
+
+ private WindowManagerService mWms;
+
+ void setWindowManager(@NonNull WindowManagerService wms) {
+ mWms = wms;
+ }
/**
* Schedules a transaction, which may consist of multiple callbacks and a lifecycle request.
@@ -82,14 +98,24 @@ class ClientLifecycleManager {
*/
void scheduleTransactionItem(@NonNull IApplicationThread client,
@NonNull ClientTransactionItem transactionItem) throws RemoteException {
- // TODO(b/260873529): queue the transaction items.
- final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
- if (transactionItem.isActivityLifecycleItem()) {
- clientTransaction.setLifecycleStateRequest((ActivityLifecycleItem) transactionItem);
+ // The behavior is different depending on the flag.
+ // When flag is on, we wait until RootWindowContainer#performSurfacePlacementNoTrace to
+ // dispatch all pending transactions at once.
+ if (Flags.bundleClientTransactionFlag()) {
+ final ClientTransaction clientTransaction = getOrCreatePendingTransaction(client);
+ clientTransaction.addTransactionItem(transactionItem);
+
+ onClientTransactionItemScheduledLocked(clientTransaction);
} else {
- clientTransaction.addCallback(transactionItem);
+ // TODO(b/260873529): cleanup after launch.
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
+ if (transactionItem.isActivityLifecycleItem()) {
+ clientTransaction.setLifecycleStateRequest((ActivityLifecycleItem) transactionItem);
+ } else {
+ clientTransaction.addCallback(transactionItem);
+ }
+ scheduleTransaction(clientTransaction);
}
- scheduleTransaction(clientTransaction);
}
/**
@@ -100,10 +126,67 @@ class ClientLifecycleManager {
void scheduleTransactionAndLifecycleItems(@NonNull IApplicationThread client,
@NonNull ClientTransactionItem transactionItem,
@NonNull ActivityLifecycleItem lifecycleItem) throws RemoteException {
- // TODO(b/260873529): replace with #scheduleTransactionItem after launch for cleanup.
- final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
- clientTransaction.addCallback(transactionItem);
- clientTransaction.setLifecycleStateRequest(lifecycleItem);
+ // The behavior is different depending on the flag.
+ // When flag is on, we wait until RootWindowContainer#performSurfacePlacementNoTrace to
+ // dispatch all pending transactions at once.
+ if (Flags.bundleClientTransactionFlag()) {
+ final ClientTransaction clientTransaction = getOrCreatePendingTransaction(client);
+ clientTransaction.addTransactionItem(transactionItem);
+ clientTransaction.addTransactionItem(lifecycleItem);
+
+ onClientTransactionItemScheduledLocked(clientTransaction);
+ } else {
+ // TODO(b/260873529): cleanup after launch.
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
+ clientTransaction.addCallback(transactionItem);
+ clientTransaction.setLifecycleStateRequest(lifecycleItem);
+ scheduleTransaction(clientTransaction);
+ }
+ }
+
+ /** Executes all the pending transactions. */
+ void dispatchPendingTransactions() {
+ final int size = mPendingTransactions.size();
+ for (int i = 0; i < size; i++) {
+ final ClientTransaction transaction = mPendingTransactions.valueAt(i);
+ try {
+ scheduleTransaction(transaction);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to deliver transaction for " + transaction.getClient());
+ }
+ }
+ mPendingTransactions.clear();
+ }
+
+ @NonNull
+ private ClientTransaction getOrCreatePendingTransaction(@NonNull IApplicationThread client) {
+ final IBinder clientBinder = client.asBinder();
+ final ClientTransaction pendingTransaction = mPendingTransactions.get(clientBinder);
+ if (pendingTransaction != null) {
+ return pendingTransaction;
+ }
+
+ // Create new transaction if there is no existing.
+ final ClientTransaction transaction = ClientTransaction.obtain(client);
+ mPendingTransactions.put(clientBinder, transaction);
+ return transaction;
+ }
+
+ /** Must only be called with WM lock. */
+ private void onClientTransactionItemScheduledLocked(
+ @NonNull ClientTransaction clientTransaction) throws RemoteException {
+ // TODO(b/260873529): make sure WindowSurfacePlacer#requestTraversal is called before
+ // ClientTransaction scheduled when needed.
+
+ if (mWms != null && (mWms.mWindowPlacerLocked.isInLayout()
+ || mWms.mWindowPlacerLocked.isTraversalScheduled())) {
+ // The pending transactions will be dispatched when
+ // RootWindowContainer#performSurfacePlacementNoTrace.
+ return;
+ }
+
+ // Dispatch the pending transaction immediately.
+ mPendingTransactions.remove(clientTransaction.getClient().asBinder());
scheduleTransaction(clientTransaction);
}
}
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 4a3d0c142e1d..32d60c5f52e6 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.input.flags.Flags.enablePointerChoreographer;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -23,6 +24,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
import android.content.ClipData;
import android.content.Context;
+import android.hardware.input.InputManagerGlobal;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -31,6 +33,8 @@ import android.os.Message;
import android.util.Slog;
import android.view.Display;
import android.view.IWindow;
+import android.view.InputDevice;
+import android.view.PointerIcon;
import android.view.SurfaceControl;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
@@ -97,8 +101,8 @@ class DragDropController {
}
IBinder performDrag(int callerPid, int callerUid, IWindow window, int flags,
- SurfaceControl surface, int touchSource, float touchX, float touchY,
- float thumbCenterX, float thumbCenterY, ClipData data) {
+ SurfaceControl surface, int touchSource, int touchDeviceId, int touchPointerId,
+ float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "perform drag: win=" + window + " surface=" + surface + " flags=" +
Integer.toHexString(flags) + " data=" + data + " touch(" + touchX + ","
@@ -208,7 +212,17 @@ class DragDropController {
final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
mDragState.broadcastDragStartedLocked(touchX, touchY);
- mDragState.overridePointerIconLocked(touchSource);
+ if (enablePointerChoreographer()) {
+ if ((touchSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
+ InputManagerGlobal.getInstance().setPointerIcon(
+ PointerIcon.getSystemIcon(
+ mService.mContext, PointerIcon.TYPE_GRABBING),
+ mDragState.mDisplayContent.getDisplayId(), touchDeviceId,
+ touchPointerId, mDragState.getInputToken());
+ }
+ } else {
+ mDragState.overridePointerIconLocked(touchSource);
+ }
// remember the thumb offsets for later
mDragState.mThumbOffsetX = thumbCenterX;
mDragState.mThumbOffsetY = thumbCenterY;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index a888f8467b3a..adbe3bc1d6b3 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -416,6 +416,13 @@ class DragState {
return mInputInterceptor == null ? null : mInputInterceptor.mDragWindowHandle;
}
+ IBinder getInputToken() {
+ if (mInputInterceptor == null || mInputInterceptor.mClientChannel == null) {
+ return null;
+ }
+ return mInputInterceptor.mClientChannel.getToken();
+ }
+
/**
* @param display The Display that the window being dragged is on.
*/
diff --git a/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java b/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java
index 9cbc1bdcbeeb..4c73a415d3f3 100644
--- a/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java
+++ b/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java
@@ -84,10 +84,10 @@ class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implement
}
@Override
- public void onActivityLaunched(long id, ComponentName name, int temperature) {
+ public void onActivityLaunched(long id, ComponentName name, int temperature, int userId) {
mHandler.sendMessage(PooledLambda.obtainMessage(
LaunchObserverRegistryImpl::handleOnActivityLaunched,
- this, id, name, temperature));
+ this, id, name, temperature, userId));
}
@Override
@@ -97,10 +97,11 @@ class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implement
}
@Override
- public void onActivityLaunchFinished(long id, ComponentName name, long timestampNs) {
+ public void onActivityLaunchFinished(long id, ComponentName name, long timestampNs,
+ int launchMode) {
mHandler.sendMessage(PooledLambda.obtainMessage(
LaunchObserverRegistryImpl::handleOnActivityLaunchFinished,
- this, id, name, timestampNs));
+ this, id, name, timestampNs, launchMode));
}
@Override
@@ -137,10 +138,10 @@ class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implement
}
private void handleOnActivityLaunched(long id, ComponentName name,
- @Temperature int temperature) {
+ @Temperature int temperature, int userId) {
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
for (int i = 0; i < mList.size(); i++) {
- mList.get(i).onActivityLaunched(id, name, temperature);
+ mList.get(i).onActivityLaunched(id, name, temperature, userId);
}
}
@@ -151,10 +152,11 @@ class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implement
}
}
- private void handleOnActivityLaunchFinished(long id, ComponentName name, long timestampNs) {
+ private void handleOnActivityLaunchFinished(long id, ComponentName name, long timestampNs,
+ int launchMode) {
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
for (int i = 0; i < mList.size(); i++) {
- mList.get(i).onActivityLaunchFinished(id, name, timestampNs);
+ mList.get(i).onActivityLaunchFinished(id, name, timestampNs, launchMode);
}
}
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/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index d5aa2760d41a..9a75dae3569e 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -842,6 +842,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
handleResizingWindows();
clearFrameChangingWindows();
+ // Called after #handleResizingWindows to include WindowStateResizeItem if any.
+ mWmService.mAtmService.getLifecycleManager().dispatchPendingTransactions();
+
if (mWmService.mDisplayFrozen) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
"With display frozen, orientationChangeComplete=%b",
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 56f9aa4c6361..57939bc4f348 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -340,7 +340,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
- float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
+ int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX,
+ float thumbCenterY, ClipData data) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
// Validate and resolve ClipDescription data before clearing the calling identity
@@ -349,7 +350,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
final long ident = Binder.clearCallingIdentity();
try {
return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
- touchX, touchY, thumbCenterX, thumbCenterY, data);
+ touchDeviceId, touchPointerId, touchX, touchY, thumbCenterX, thumbCenterY,
+ data);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index fc92755c6550..5d019122d52e 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -73,6 +73,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
+import android.app.IApplicationThread;
import android.app.ResultInfo;
import android.app.WindowConfiguration;
import android.app.servertransaction.ActivityResultItem;
@@ -103,6 +104,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.am.HostingRecord;
import com.android.server.pm.pkg.AndroidPackage;
+import com.android.window.flags.Flags;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -1509,23 +1511,38 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
try {
- final ClientTransaction transaction = ClientTransaction.obtain(
- next.app.getThread());
+ final IApplicationThread appThread = next.app.getThread();
+ final ClientTransaction transaction = Flags.bundleClientTransactionFlag()
+ ? null
+ : ClientTransaction.obtain(appThread);
// Deliver all pending results.
- ArrayList<ResultInfo> a = next.results;
+ final ArrayList<ResultInfo> a = next.results;
if (a != null) {
final int size = a.size();
if (!next.finishing && size > 0) {
if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
}
- transaction.addCallback(ActivityResultItem.obtain(next.token, a));
+ final ActivityResultItem activityResultItem = ActivityResultItem.obtain(
+ next.token, a);
+ if (transaction == null) {
+ mAtmService.getLifecycleManager().scheduleTransactionItem(
+ appThread, activityResultItem);
+ } else {
+ transaction.addCallback(activityResultItem);
+ }
}
}
if (next.newIntents != null) {
- transaction.addCallback(
- NewIntentItem.obtain(next.token, next.newIntents, true /* resume */));
+ final NewIntentItem newIntentItem = NewIntentItem.obtain(
+ next.token, next.newIntents, true /* resume */);
+ if (transaction == null) {
+ mAtmService.getLifecycleManager().scheduleTransactionItem(
+ appThread, newIntentItem);
+ } else {
+ transaction.addCallback(newIntentItem);
+ }
}
// Well the app will no longer be stopped.
@@ -1539,10 +1556,16 @@ class TaskFragment extends WindowContainer<WindowContainer> {
final int topProcessState = mAtmService.mTopProcessState;
next.app.setPendingUiCleanAndForceProcessStateUpTo(topProcessState);
next.abortAndClearOptionsAnimation();
- transaction.setLifecycleStateRequest(
- ResumeActivityItem.obtain(next.token, topProcessState,
- dc.isNextTransitionForward(), next.shouldSendCompatFakeFocus()));
- mAtmService.getLifecycleManager().scheduleTransaction(transaction);
+ final ResumeActivityItem resumeActivityItem = ResumeActivityItem.obtain(
+ next.token, topProcessState, dc.isNextTransitionForward(),
+ next.shouldSendCompatFakeFocus());
+ if (transaction == null) {
+ mAtmService.getLifecycleManager().scheduleTransactionItem(
+ appThread, resumeActivityItem);
+ } else {
+ transaction.setLifecycleStateRequest(resumeActivityItem);
+ mAtmService.getLifecycleManager().scheduleTransaction(transaction);
+ }
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next);
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 808a11d4adae..516d37c0136a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -866,6 +866,11 @@ public abstract class WindowManagerInternal {
public abstract ImeTargetInfo onToggleImeRequested(boolean show,
@NonNull IBinder focusedToken, @NonNull IBinder requestToken, int displayId);
+ /**
+ * Returns the token to identify the target window that the IME is associated with.
+ */
+ public abstract @Nullable IBinder getTargetWindowTokenFromInputToken(IBinder inputToken);
+
/** The information of input method target when IME is requested to show or hide. */
public static class ImeTargetInfo {
public final String focusedWindowName;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 10dd334ed50c..2125c63eed34 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8552,6 +8552,12 @@ public class WindowManagerService extends IWindowManager.Stub
fromOrientations, toOrientations);
}
}
+
+ @Override
+ public @Nullable IBinder getTargetWindowTokenFromInputToken(IBinder inputToken) {
+ InputTarget inputTarget = WindowManagerService.this.getInputTargetFromToken(inputToken);
+ return inputTarget == null ? null : inputTarget.getWindowToken();
+ }
}
private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index aa589024fdc6..dff718a4b7d5 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -210,6 +210,10 @@ class WindowSurfacePlacer {
return mInLayout;
}
+ boolean isTraversalScheduled() {
+ return mTraversalScheduled;
+ }
+
void requestTraversal() {
if (mTraversalScheduled) {
return;
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 3d4f866948af..2a0f1e2ede55 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -182,7 +182,7 @@ static inline IncFsSize verityTreeSizeForFile(IncFsSize fileSize) {
auto block_count = 1 + (fileSize - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
auto hash_block_count = block_count;
- for (auto i = 0; hash_block_count > 1; i++) {
+ while (hash_block_count > 1) {
hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
total_tree_block_count += hash_block_count;
}
@@ -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/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 02032c786563..f69f6283f968 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -24,6 +24,7 @@ import android.content.pm.SigningDetails
import android.os.Build
import android.util.Slog
import com.android.internal.os.RoSystemProperties
+import com.android.internal.pm.permission.CompatibilityPermissionInfo
import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.AccessState
@@ -42,7 +43,6 @@ import com.android.server.permission.access.util.hasBits
import com.android.server.permission.access.util.isInternal
import com.android.server.pm.KnownPackages
import com.android.server.pm.parsing.PackageInfoUtils
-import com.android.server.pm.permission.CompatibilityPermissionInfo
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageState
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index d62da1a02525..5b222c01d56b 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -57,11 +57,11 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.core.app.ApplicationProvider;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowUserManager;
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 3011fa17d4fc..5c4716dc751e 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -25,6 +25,7 @@ import android.os.Binder
import android.os.UserHandle
import android.util.ArrayMap
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.parsing.pkg.ParsedPackage
import com.android.internal.pm.pkg.component.ParsedActivity
import com.android.server.pm.AppsFilterImpl
@@ -38,7 +39,6 @@ import com.android.server.pm.Settings
import com.android.server.pm.SharedLibrariesImpl
import com.android.server.pm.UserManagerInternal
import com.android.server.pm.UserManagerService
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.resolution.ComponentResolver
import com.android.server.pm.snapshot.PackageDataSnapshot
@@ -49,6 +49,8 @@ import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import com.android.server.wm.ActivityTaskManagerInternal
import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.UUID
import org.junit.After
import org.junit.Before
import org.junit.BeforeClass
@@ -61,8 +63,6 @@ import org.mockito.Mockito.doReturn
import org.mockito.Mockito.intThat
import org.mockito.Mockito.same
import org.testng.Assert.assertThrows
-import java.io.File
-import java.util.UUID
@RunWith(Parameterized::class)
class PackageManagerComponentLabelIconOverrideTest {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
index 3461bb6b2c55..7277fd79fdd5 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
@@ -49,20 +49,20 @@ import android.util.SparseArray;
import androidx.annotation.NonNull;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
+import com.android.internal.pm.pkg.component.ParsedComponentImpl;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
import com.android.internal.pm.pkg.component.ParsedPermission;
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.om.OverlayReferenceMapper;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedComponentImpl;
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionImpl;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.server.utils.WatchableTester;
import org.junit.Before;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java
index f0d389be7cb6..b1c3e94c2138 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java
@@ -32,11 +32,11 @@ import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.platform.test.annotations.Presubmit;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.PackageStateUnserialized;
import com.android.server.pm.pkg.PackageUserStateImpl;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import org.junit.After;
import org.junit.Before;
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 f07e820bf8b3..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;
@@ -63,10 +67,11 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+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.pkg.PackageImpl;
+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/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
index 9c48af8ecd01..285c059e973a 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
@@ -73,7 +73,7 @@ import androidx.test.filters.Suppress;
import com.android.compatibility.common.util.CddTest;
import com.android.internal.content.InstallLocationUtils;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.parsing.ParsingUtils;
import com.android.server.pm.test.service.server.R;
import dalvik.system.VMRuntime;
@@ -346,7 +346,7 @@ public class PackageManagerTests extends AndroidTestCase {
private ParsedPackage parsePackage(Uri packageURI) {
final String archiveFilePath = packageURI.getPath();
- ParseResult<ParsedPackage> result = ParsingPackageUtils.parseDefaultOneTime(
+ ParseResult<ParsedPackage> result = ParsingUtils.parseDefaultOneTime(
new File(archiveFilePath), 0 /*flags*/, Collections.emptyList(),
false /*collectCertificates*/);
if (result.isError()) {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index a62cd4fc5fc2..03e45a27390f 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -15,7 +15,7 @@
*/
package com.android.server.pm;
-import static com.android.server.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
+import static com.android.internal.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -58,17 +58,28 @@ import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.permission.CompatibilityPermissionInfo;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl;
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.component.ParsedServiceImpl;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.parsing.PackageCacher;
@@ -76,19 +87,8 @@ import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.permission.CompatibilityPermissionInfo;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageUserStateInternal;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
-import com.android.server.pm.pkg.component.ParsedServiceImpl;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
import org.junit.Before;
import org.junit.Rule;
@@ -725,6 +725,16 @@ public class PackageParserTest {
public boolean hasFeature(String feature) {
return false;
}
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return new ArraySet<>();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return new ArraySet<>();
+ }
});
if (cacheDir != null) {
setCacheDir(cacheDir);
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/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
index 6202908cdfbf..c1271bb0ee36 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
@@ -50,13 +50,13 @@ import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import org.hamcrest.BaseMatcher;
@@ -376,7 +376,7 @@ public class ScanTests {
// Create the ParsedPackage for the apex
final ParsedPackage basicPackage =
((ParsedPackage) new PackageImpl(DUMMY_PACKAGE_NAME, codePath, codePath,
- mock(TypedArray.class), false)
+ mock(TypedArray.class), false, null)
.setVolumeUuid(UUID_ONE.toString())
.hideAsParsed())
.setVersionCodeMajor(1)
@@ -595,7 +595,7 @@ public class ScanTests {
// TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps
return (ParsingPackage) ((ParsedPackage) new PackageImpl(packageName,
"/data/tmp/randompath/base.apk", createCodePath(packageName),
- mock(TypedArray.class), false)
+ mock(TypedArray.class), false, null)
.setVolumeUuid(UUID_ONE.toString())
.addUsesStaticLibrary("some.static.library", 234L, new String[]{"testCert1"})
.addUsesStaticLibrary("some.other.static.library", 456L, new String[]{"testCert2"})
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index b102ab4f7e3b..b63950c10a18 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -39,14 +39,14 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ParsedActivityUtils;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.PackageManagerException;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.component.ParsedActivityUtils;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
import com.android.server.pm.test.service.server.R;
import com.google.common.truth.Expect;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
index 67b91d2646d9..c435b94fcacd 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
@@ -22,7 +22,6 @@ import android.content.pm.parsing.result.ParseResult
import android.platform.test.annotations.Presubmit
import androidx.test.InstrumentationRegistry
import com.android.internal.pm.parsing.pkg.ParsedPackage
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.test.service.server.R
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
@@ -121,7 +120,7 @@ class PackageParsingDeferErrorTest {
input.copyTo(output)
}
}
- return ParsingPackageUtils.parseDefaultOneTime(file, 0 /*flags*/, emptyList(),
+ return ParsingUtils.parseDefaultOneTime(file, 0 /*flags*/, emptyList(),
false /*collectCertificates*/)
}
}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java
new file mode 100644
index 000000000000..a9eac95dfd87
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java
@@ -0,0 +1,81 @@
+/*
+ * 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.pm.parsing;
+
+import android.annotation.NonNull;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.res.TypedArray;
+import android.permission.PermissionManager;
+
+import com.android.internal.pm.parsing.pkg.PackageImpl;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.SystemConfig;
+
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+
+/** @hide **/
+public class ParsingUtils {
+
+ /**
+ * @see ParsingPackageUtils#parseDefault(ParseInput, File, int, List, boolean,
+ * ParsingPackageUtils.Callback)
+ */
+ @NonNull
+ public static ParseResult<ParsedPackage> parseDefaultOneTime(File file,
+ @ParsingPackageUtils.ParseFlags int parseFlags,
+ @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
+ boolean collectCertificates) {
+ ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
+ return ParsingPackageUtils.parseDefault(input, file, parseFlags, splitPermissions, collectCertificates,
+ new ParsingPackageUtils.Callback() {
+ @Override
+ public boolean hasFeature(String feature) {
+ // Assume the device doesn't support anything. This will affect permission
+ // parsing and will force <uses-permission/> declarations to include all
+ // requiredNotFeature permissions and exclude all requiredFeature
+ // permissions. This mirrors the old behavior.
+ return false;
+ }
+
+ @Override
+ public ParsingPackage startParsingPackage(
+ @NonNull String packageName,
+ @NonNull String baseApkPath,
+ @NonNull String path,
+ @NonNull TypedArray manifestArray, boolean isCoreApp) {
+ return PackageImpl.forParsing(packageName, baseApkPath, path, manifestArray,
+ isCoreApp, this);
+ }
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ }
+ });
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
index 1f57b6c9f95f..98af63c65e90 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
@@ -17,15 +17,15 @@
package com.android.server.pm.parsing
import android.content.pm.PackageManager
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import android.platform.test.annotations.Postsubmit
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.PackageManagerException
import com.android.server.pm.PackageManagerService
import com.android.server.pm.PackageManagerServiceUtils
+import java.io.File
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
-import java.io.File
/**
* This test parses all the system APKs on the device image to ensure that they succeed.
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
index 6cd71237efa2..9517e49c4a73 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
@@ -24,8 +24,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
index 27fd781584f2..01fad8f57d16 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
@@ -21,8 +21,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
index b13d6de55cf6..b1f26c253043 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
@@ -23,8 +23,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
index fa69f844c33a..349763ae18b3 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
@@ -24,9 +24,9 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
index 856013a96017..71bdacbce9f7 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
@@ -22,9 +22,9 @@ import android.util.ArrayMap;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Before;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
index ae5ea21aec4e..6aa0c2db4d39 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
@@ -21,8 +21,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
index e126ffcab5ff..44098d0be2b2 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
@@ -23,8 +23,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
index d0b0cf894340..9d5ce8a66395 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -28,10 +28,10 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Assume;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
index c141c0337540..bffeb7255b31 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -23,9 +23,9 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
index a58604b81e06..b114cd375050 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -23,9 +23,9 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 09b66c11d200..ef9c62fd3795 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -30,21 +30,21 @@ import android.util.ArraySet
import android.util.SparseArray
import android.util.SparseIntArray
import com.android.internal.R
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils
-import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils
+import com.android.internal.pm.parsing.pkg.PackageImpl
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedApexSystemServiceImpl
+import com.android.internal.pm.pkg.component.ParsedAttributionImpl
+import com.android.internal.pm.pkg.component.ParsedComponentImpl
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl
+import com.android.internal.pm.pkg.component.ParsedProcessImpl
+import com.android.internal.pm.pkg.component.ParsedProviderImpl
+import com.android.internal.pm.pkg.component.ParsedServiceImpl
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl
-import com.android.server.pm.pkg.component.ParsedAttributionImpl
-import com.android.server.pm.pkg.component.ParsedComponentImpl
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
-import com.android.server.pm.pkg.component.ParsedPermissionImpl
-import com.android.server.pm.pkg.component.ParsedProcessImpl
-import com.android.server.pm.pkg.component.ParsedProviderImpl
-import com.android.server.pm.pkg.component.ParsedServiceImpl
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import java.security.KeyPairGenerator
@@ -534,34 +534,34 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
}
),
getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT")),
- getSetByValue({ AndroidPackageUtils.isOdm(it) }, "isOdm", PackageImpl::setOdm, true),
- getSetByValue({ AndroidPackageUtils.isOem(it) }, "isOem", PackageImpl::setOem, true),
+ getSetByValue({ AndroidPackageLegacyUtils.isOdm(it) }, "isOdm", PackageImpl::setOdm, true),
+ getSetByValue({ AndroidPackageLegacyUtils.isOem(it) }, "isOem", PackageImpl::setOem, true),
getSetByValue(
- { AndroidPackageUtils.isPrivileged(it) },
+ { AndroidPackageLegacyUtils.isPrivileged(it) },
"isPrivileged",
PackageImpl::setPrivileged,
true
),
getSetByValue(
- { AndroidPackageUtils.isProduct(it) },
+ { AndroidPackageLegacyUtils.isProduct(it) },
"isProduct",
PackageImpl::setProduct,
true
),
getSetByValue(
- { AndroidPackageUtils.isVendor(it) },
+ { AndroidPackageLegacyUtils.isVendor(it) },
"isVendor",
PackageImpl::setVendor,
true
),
getSetByValue(
- { AndroidPackageUtils.isSystem(it) },
+ { AndroidPackageLegacyUtils.isSystem(it) },
"isSystem",
PackageImpl::setSystem,
true
),
getSetByValue(
- { AndroidPackageUtils.isSystemExt(it) },
+ { AndroidPackageLegacyUtils.isSystemExt(it) },
"isSystemExt",
PackageImpl::setSystemExt,
true
@@ -593,7 +593,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
)
) { "" }
},
- true
+ true, null
)
.asSplit(
arrayOf("testSplitNameZero", "testSplitNameOne"),
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
index 26468544e8d6..2c8b1cd884f1 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
@@ -18,7 +18,7 @@ package com.android.server.pm.test.parsing.parcelling
import android.content.pm.ActivityInfo
import com.android.internal.pm.pkg.component.ParsedActivity
-import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
index 52d5b3bccb72..ad5374672d22 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedAttribution
-import com.android.server.pm.pkg.component.ParsedAttributionImpl
+import com.android.internal.pm.pkg.component.ParsedAttributionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
index af0c0de2db15..3ac48536b39c 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
@@ -18,8 +18,8 @@ package com.android.server.pm.test.parsing.parcelling
import android.content.pm.PackageManager
import com.android.internal.pm.pkg.component.ParsedComponent
-import com.android.server.pm.pkg.component.ParsedComponentImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.internal.pm.pkg.component.ParsedComponentImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import android.os.Bundle
import android.os.Parcelable
import kotlin.contracts.ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
index dc0f194f10cc..2bd4f617dcb5 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedInstrumentation
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
index 5224f23d38d1..af385e202a9e 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedIntentInfo
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import android.os.Parcelable
import android.os.PatternMatcher
import kotlin.contracts.ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
index dfff6025e2eb..061e39ddf6df 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedMainComponent
-import com.android.server.pm.pkg.component.ParsedMainComponentImpl
+import com.android.internal.pm.pkg.component.ParsedMainComponentImpl
import android.os.Parcelable
import java.util.Arrays
import kotlin.contracts.ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
index ccbf558734d3..3a6418824dfa 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedPermissionGroup
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
index 2814783b6849..551f16d2a3bb 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
@@ -18,8 +18,8 @@ package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedPermission
import com.android.internal.pm.pkg.component.ParsedPermissionGroup
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
-import com.android.server.pm.pkg.component.ParsedPermissionImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
index 2e9604696acb..93bdeaeb90e3 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
@@ -16,9 +16,9 @@
package com.android.server.pm.test.parsing.parcelling
-import com.android.internal.pm.pkg.component.ParsedProcess
-import com.android.server.pm.pkg.component.ParsedProcessImpl
import android.util.ArrayMap
+import com.android.internal.pm.pkg.component.ParsedProcess
+import com.android.internal.pm.pkg.component.ParsedProcessImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
index 290dbd6277b6..1e844705fe3c 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
@@ -17,9 +17,9 @@
package com.android.server.pm.test.parsing.parcelling
import android.content.pm.PathPermission
-import com.android.internal.pm.pkg.component.ParsedProvider
-import com.android.server.pm.pkg.component.ParsedProviderImpl
import android.os.PatternMatcher
+import com.android.internal.pm.pkg.component.ParsedProvider
+import com.android.internal.pm.pkg.component.ParsedProviderImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
index 3ae7e9220cc6..79d5a4f7030a 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedService
-import com.android.server.pm.pkg.component.ParsedServiceImpl
+import com.android.internal.pm.pkg.component.ParsedServiceImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
index 67dfc6d4f7ef..d0ad09be982b 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedUsesPermission
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
index 1da3a2234ffc..b21c34905bad 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
@@ -17,37 +17,34 @@
package com.android.server.pm.test.pkg
import android.content.Intent
-import android.content.pm.overlay.OverlayPaths
import android.content.pm.PackageManager
import android.content.pm.PathPermission
import android.content.pm.SharedLibraryInfo
import android.content.pm.VersionedPackage
+import android.content.pm.overlay.OverlayPaths
import android.os.PatternMatcher
import android.util.ArraySet
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.pkg.component.ParsedActivity
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedComponentImpl
import com.android.internal.pm.pkg.component.ParsedInstrumentation
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.internal.pm.pkg.component.ParsedPermission
import com.android.internal.pm.pkg.component.ParsedPermissionGroup
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl
import com.android.internal.pm.pkg.component.ParsedProcess
+import com.android.internal.pm.pkg.component.ParsedProcessImpl
import com.android.internal.pm.pkg.component.ParsedProvider
+import com.android.internal.pm.pkg.component.ParsedProviderImpl
import com.android.internal.pm.pkg.component.ParsedService
import com.android.server.pm.PackageSetting
import com.android.server.pm.PackageSettingBuilder
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageState
import com.android.server.pm.pkg.PackageUserState
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedComponentImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
-import com.android.server.pm.pkg.component.ParsedPermissionImpl
-import com.android.server.pm.pkg.component.ParsedProcessImpl
-import com.android.server.pm.pkg.component.ParsedProviderImpl
import com.android.server.pm.test.parsing.parcelling.AndroidPackageTest
import com.google.common.truth.Expect
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
import kotlin.contracts.ExperimentalContracts
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
@@ -55,6 +52,9 @@ import kotlin.reflect.KType
import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.full.memberFunctions
import kotlin.reflect.full.starProjectedType
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
class PackageStateTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
index 9341e9d96335..5e73d198f528 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
@@ -22,11 +22,11 @@ import android.os.Build
import android.os.PatternMatcher
import android.util.ArraySet
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.SystemConfig
import com.android.server.compat.PlatformCompat
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationCollector
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index a737b9097b53..d307608e0be2 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -29,17 +29,22 @@ import android.util.IndentingPrintWriter
import android.util.SparseArray
import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.Computer
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationEnforcer
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
+import java.util.UUID
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.atomic.AtomicInteger
+import kotlin.test.assertFailsWith
+import kotlin.test.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -51,11 +56,6 @@ import org.mockito.Mockito.doReturn
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.verifyNoMoreInteractions
-import java.util.UUID
-import java.util.concurrent.atomic.AtomicBoolean
-import java.util.concurrent.atomic.AtomicInteger
-import kotlin.test.assertFailsWith
-import kotlin.test.fail
@RunWith(Parameterized::class)
class DomainVerificationEnforcerTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index f38df22af630..5edf30a33def 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -30,24 +30,24 @@ import android.os.Process
import android.util.ArraySet
import android.util.SparseArray
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationManagerStub
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
+import java.util.UUID
+import java.util.concurrent.atomic.AtomicBoolean
+import kotlin.test.assertFailsWith
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.doReturn
-import java.util.UUID
-import java.util.concurrent.atomic.AtomicBoolean
-import kotlin.test.assertFailsWith
class DomainVerificationManagerApiTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index 874e0d2bbc9a..85f012534113 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -37,27 +37,27 @@ import android.util.ArraySet
import android.util.SparseArray
import android.util.Xml
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.Computer
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.testutils.mock
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.spy
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.security.PublicKey
+import java.util.UUID
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.doReturn
-import java.io.ByteArrayInputStream
-import java.io.ByteArrayOutputStream
-import java.security.PublicKey
-import java.util.UUID
class DomainVerificationPackageTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 3207e6c2a411..a5c4f6cc0289 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -25,15 +25,16 @@ import android.os.Process
import android.util.ArraySet
import android.util.SparseArray
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
+import java.util.UUID
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -44,7 +45,6 @@ import org.mockito.Mockito.anyString
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.eq
import org.mockito.Mockito.verify
-import java.util.UUID
@RunWith(Parameterized::class)
class DomainVerificationSettingsMutationTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index a90b7d5ec7da..ae570a3a0ee2 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -27,14 +27,15 @@ import android.os.Process
import android.util.ArraySet
import android.util.SparseArray
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
+import java.util.UUID
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
@@ -42,8 +43,6 @@ import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.doReturn
-import java.util.UUID
-
class DomainVerificationUserStateOverrideTest {
companion object {
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/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index 76d4d55f4d5d..9739e4b46063 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -2423,6 +2423,14 @@ public class GameManagerServiceTests {
}
}));
+ when(mSysPropsMock.getInt(
+ ArgumentMatchers.eq(PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE),
+ anyInt())).thenReturn(60);
+ when(mSysPropsMock.getBoolean(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq(true))).thenReturn(true);
+ gameManagerService.onBootCompleted();
+
// Set up a game in the foreground.
String[] packages = {mPackageName};
when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
@@ -2430,12 +2438,6 @@ public class GameManagerServiceTests {
DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TOP, 0, 0);
// Toggle game default frame rate on.
- when(mSysPropsMock.getInt(
- ArgumentMatchers.eq(PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE),
- anyInt())).thenReturn(60);
- when(mSysPropsMock.getBoolean(
- ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
- ArgumentMatchers.eq(true))).thenReturn(true);
gameManagerService.toggleGameDefaultFrameRate(true);
// Verify that:
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java
index 23886a17c890..00fe3d92413c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java
@@ -25,6 +25,7 @@ import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BACKGROUND
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -167,8 +168,12 @@ public class BackgroundJobsControllerTest {
}
private void setStoppedState(int uid, String pkgName, boolean stopped) {
- doReturn(stopped).when(mPackageManagerInternal).isPackageStopped(pkgName, uid);
- sendPackageStoppedBroadcast(uid, pkgName, stopped);
+ try {
+ doReturn(stopped).when(mPackageManagerInternal).isPackageStopped(pkgName, uid);
+ sendPackageStoppedBroadcast(uid, pkgName, stopped);
+ } catch (PackageManager.NameNotFoundException e) {
+ fail("Unable to set stopped state for unknown package: " + pkgName);
+ }
}
private void sendPackageStoppedBroadcast(int uid, String pkgName, boolean stopped) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
index de8b3080907c..c2b52b4ee9c8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -45,14 +45,15 @@ import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.platform.test.annotations.Presubmit;
+import android.util.ArraySet;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import org.junit.Before;
import org.junit.Rule;
@@ -67,6 +68,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
@SmallTest
@Presubmit
@@ -106,6 +108,18 @@ public class ApexManagerTest {
public boolean hasFeature(String feature) {
return true;
}
+
+ @androidx.annotation.NonNull
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return new ArraySet<>();
+ }
+
+ @androidx.annotation.NonNull
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return new ArraySet<>();
+ }
});
mMockSystem.system().stageNominalSystemState();
@@ -385,7 +399,7 @@ public class ApexManagerTest {
findFactory(results, "test.apex.rebootless").apexInfo);
assertThat(factoryPkg.getBaseApkPath()).isEqualTo(activeApexInfo.modulePath);
assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1);
- assertThat(AndroidPackageUtils.isSystem(factoryPkg)).isTrue();
+ assertThat(AndroidPackageLegacyUtils.isSystem(factoryPkg)).isTrue();
}
@Test
@@ -416,7 +430,7 @@ public class ApexManagerTest {
findFactory(results, "test.apex.rebootless").apexInfo);
assertThat(factoryPkg.getBaseApkPath()).isEqualTo(factoryApexInfo.modulePath);
assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1);
- assertThat(AndroidPackageUtils.isSystem(factoryPkg)).isTrue();
+ assertThat(AndroidPackageLegacyUtils.isSystem(factoryPkg)).isTrue();
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 28bd98781ced..7b29e2a4159d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -56,8 +56,10 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.spy
import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder
import com.android.internal.R
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.parsing.pkg.ParsedPackage
import com.android.internal.pm.pkg.parsing.ParsingPackage
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.LocalManagerRegistry
import com.android.server.LocalServices
import com.android.server.LockGuard
@@ -68,10 +70,8 @@ import com.android.server.extendedtestutils.wheneverStatic
import com.android.server.pm.dex.DexManager
import com.android.server.pm.dex.DynamicCodeLogger
import com.android.server.pm.parsing.PackageParser2
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.resolution.ComponentResolver
import com.android.server.pm.snapshot.PackageDataSnapshot
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
@@ -81,14 +81,6 @@ import com.android.server.testutils.mock
import com.android.server.testutils.nullable
import com.android.server.testutils.whenever
import com.android.server.utils.WatchedArrayMap
-import libcore.util.HexEncoding
-import org.junit.Assert
-import org.junit.rules.TestRule
-import org.junit.runner.Description
-import org.junit.runners.model.Statement
-import org.mockito.AdditionalMatchers.or
-import org.mockito.Mockito
-import org.mockito.quality.Strictness
import java.io.File
import java.io.IOException
import java.nio.file.Files
@@ -97,6 +89,14 @@ import java.security.cert.CertificateException
import java.util.Arrays
import java.util.Random
import java.util.concurrent.FutureTask
+import libcore.util.HexEncoding
+import org.junit.Assert
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import org.mockito.AdditionalMatchers.or
+import org.mockito.Mockito
+import org.mockito.quality.Strictness
/**
* A utility for mocking behavior of the system and dependencies when testing PackageManagerService
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
index 2332988cc832..e5ecdc478df7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
@@ -62,6 +62,7 @@ import android.os.ParcelableException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.text.TextUtils;
+import android.util.SparseArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -174,6 +175,7 @@ public class PackageArchiverTest {
mUserState = new PackageUserStateImpl().setInstalled(true);
mPackageSetting.setUserState(mUserId, mUserState);
when(mPackageState.getUserStateOrDefault(eq(mUserId))).thenReturn(mUserState);
+ when(mPackageState.getUserStates()).thenReturn(new SparseArray<>());
when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps);
when(mContext.getSystemService(AppOpsManager.class)).thenReturn(
@@ -343,7 +345,7 @@ public class PackageArchiverTest {
@Test
public void archiveApp_appOptedOutOfArchiving() {
- when(mAppOpsManager.checkOp(
+ when(mAppOpsManager.checkOpNoThrow(
eq(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED),
anyInt(), eq(PACKAGE))).thenReturn(MODE_IGNORED);
@@ -430,7 +432,7 @@ public class PackageArchiverTest {
@Test
public void isAppArchivable_appOptedOutOfArchiving()
throws PackageManager.NameNotFoundException {
- when(mAppOpsManager.checkOp(
+ when(mAppOpsManager.checkOpNoThrow(
eq(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED),
anyInt(), eq(PACKAGE))).thenReturn(MODE_IGNORED);
@@ -551,22 +553,12 @@ public class PackageArchiverTest {
when(mComputer.getPackageStateFiltered(eq(PACKAGE), anyInt(), anyInt())).thenReturn(
null);
- Exception e = assertThrows(
- ParcelableException.class,
- () -> mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT));
- assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
- assertThat(e.getCause()).hasMessageThat().isEqualTo(
- String.format("Package %s not found.", PACKAGE));
+ assertThat(mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT)).isNull();
}
@Test
public void getArchivedAppIcon_notArchived() {
- Exception e = assertThrows(
- ParcelableException.class,
- () -> mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT));
- assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
- assertThat(e.getCause()).hasMessageThat().isEqualTo(
- String.format("Package %s is not currently archived.", PACKAGE));
+ assertThat(mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT)).isNull();
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
index a6ba5d4c3032..7b80aea80035 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
@@ -36,6 +36,7 @@ import org.mockito.MockitoAnnotations
open class PackageHelperTestBase {
companion object {
+ const val PLATFORM_PACKAGE_NAME = "android"
const val TEST_PACKAGE_1 = "com.android.test.package1"
const val TEST_PACKAGE_2 = "com.android.test.package2"
const val DEVICE_OWNER_PACKAGE = "com.android.test.owner"
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index e685c3fa9fa4..944b1aae7bda 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -21,17 +21,17 @@ import android.content.pm.PackageManager
import android.content.pm.SharedLibraryInfo
import android.content.pm.VersionedPackage
import android.os.Build
-import android.os.storage.StorageManager
import android.os.UserHandle
+import android.os.storage.StorageManager
import android.util.ArrayMap
import android.util.PackageUtils
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.parsing.pkg.ParsedPackage
import com.android.server.SystemConfig.SharedLibraryEntry
import com.android.server.compat.PlatformCompat
import com.android.server.extendedtestutils.wheneverStatic
import com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.testutils.any
import com.android.server.testutils.eq
import com.android.server.testutils.mock
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 147303363200..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,79 @@ 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
+ fun getSuspendingPackagePrecedence() {
+ val launcherExtras = PersistableBundle()
+ launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
+ val targetPackages = arrayOf(TEST_PACKAGE_2)
+ // Suspend.
+ var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+ targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
+ 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(doUserPackage)
+
+ // Suspend by system.
+ failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+ targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
+ 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(platformUserPackage)
+
+ // QAS by package1.
+ failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+ targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
+ 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(testUserPackage1)
+
+ // Un-QAS by package1.
+ suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
+ targetPackages, { suspendingPackage -> suspendingPackage == testUserPackage1 },
+ TEST_USER_ID)
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(platformUserPackage)
+
+ // Un-suspend by system.
+ suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
+ 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(doUserPackage)
+
+ // Unsuspend.
+ suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
+ targetPackages, { suspendingPackage -> suspendingPackage == doUserPackage },
+ TEST_USER_ID)
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
}
@Test
@@ -288,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/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index a2a8424881d4..0973d46283ed 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -23,6 +23,7 @@ import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
import static com.android.server.hdmi.Constants.ADDR_RECORDER_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
import static com.google.common.truth.Truth.assertThat;
@@ -1712,13 +1713,14 @@ public class HdmiCecLocalDeviceTvTest {
HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
-
mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
+ assertThat(mHdmiControlService.getLocalActiveSource()).isEqualTo(
+ new ActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS));
mNativeWrapper.clearResultMessages();
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
mTestLooper.dispatchAll();
@@ -1728,8 +1730,64 @@ public class HdmiCecLocalDeviceTvTest {
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(activeSourceFromTv);
+ assertThat(mHdmiControlService.getLocalActiveSource()).isEqualTo(
+ new ActiveSource(mTvLogicalAddress, mTvPhysicalAddress));
+ }
+
+ @Test
+ public void requestActiveSourceActionComplete_validLocalActiveSource_doNotSendActiveSource() {
+ HdmiCecMessage requestActiveSource =
+ HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
+ HdmiCecMessage activeSourceFromTv =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+ mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
+ mHdmiControlService.setActiveSource(mTvLogicalAddress, mTvPhysicalAddress,
+ "HdmiCecLocalDeviceTvTest");
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
+ }
+
+ @Test
+ public void onAddressAllocated_startRequestActiveSourceAction_cancelOnDeviceSelect() {
+ HdmiCecMessage requestActiveSource =
+ HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
+ HdmiCecMessage activeSourceFromTv =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+ mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ HdmiDeviceInfo playbackDevice = HdmiDeviceInfo.cecDeviceBuilder()
+ .setLogicalAddress(ADDR_PLAYBACK_1)
+ .setPhysicalAddress(0x1000)
+ .setPortId(PORT_1)
+ .setDeviceType(HdmiDeviceInfo.DEVICE_PLAYBACK)
+ .setVendorId(0x1234)
+ .setDisplayName("Playback 1")
+ .setDevicePowerStatus(HdmiControlManager.POWER_STATUS_ON)
+ .setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B)
+ .build();
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(playbackDevice);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
+ mNativeWrapper.clearResultMessages();
+ mHdmiCecLocalDeviceTv.deviceSelect(playbackDevice.getId(), null);
+ mTestLooper.dispatchAll();
+
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
+ mTestLooper.dispatchAll();
+
+ // RequestActiveSourceAction should be cancelled and TV will not broadcast <Active Source>.
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
}
+
@Test
public void newDeviceConnectedIfOnlyOneGiveOsdNameSent() {
mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
@@ -1737,7 +1795,7 @@ public class HdmiCecLocalDeviceTvTest {
.isEmpty();
HdmiCecMessage reportPhysicalAddress =
HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
- ADDR_PLAYBACK_2, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK);
+ ADDR_PLAYBACK_2, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK);
HdmiCecMessage giveOsdName = HdmiCecMessageBuilder.buildGiveOsdNameCommand(
ADDR_TV, ADDR_PLAYBACK_2);
mNativeWrapper.onCecMessage(reportPhysicalAddress);
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/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 18961c0feef9..ee076c6bcf4b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -140,9 +140,9 @@ public class LockSettingsServiceTestable extends LockSettingsService {
}
@Override
- public ManagedProfilePasswordCache getManagedProfilePasswordCache(
+ public UnifiedProfilePasswordCache getUnifiedProfilePasswordCache(
java.security.KeyStore ks) {
- return mock(ManagedProfilePasswordCache.class);
+ return mock(UnifiedProfilePasswordCache.class);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
index dd687fd4286c..86a1358f371c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -27,9 +27,9 @@ import static org.mockito.Mockito.when;
import android.os.Build;
import android.platform.test.annotations.Presubmit;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.PackageState;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 8464969cd0f3..ee93bc1e3562 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -53,10 +53,10 @@ import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.UiDevice;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.After;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 0f87202f8939..587f5fa9c623 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -29,9 +29,9 @@ import android.util.SparseArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import dalvik.system.DelegateLastClassLoader;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
index ee23a00f27d7..9b4ca2a86f2c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
@@ -21,17 +21,17 @@ import android.os.Environment
import android.os.SystemProperties.PROP_VALUE_MAX
import android.platform.test.annotations.Postsubmit
import com.android.internal.R
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.PackageManagerService
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import java.io.File
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Assert.fail
import org.junit.Test
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserFactory
-import java.io.ByteArrayInputStream
-import java.io.File
@Postsubmit
class AndroidPackageParsingValidationTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
index 2332817911f7..c44f583a93ef 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
@@ -17,6 +17,7 @@
package com.android.server.pm.parsing
import android.content.pm.ApplicationInfo
+import android.util.ArraySet
import java.io.File
class TestPackageParser2(var cacheDir: File? = null) : PackageParser2(
@@ -33,4 +34,7 @@ class TestPackageParser2(var cacheDir: File? = null) : PackageParser2(
// behavior.
return false
}
+
+ override fun getHiddenApiWhitelistedApps() = ArraySet<String>()
+ override fun getInstallConstraintsAllowlist() = ArraySet<String>()
})
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
index 5ba4851270fd..759b204516c6 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
@@ -32,8 +32,9 @@ import android.content.rollback.PackageRollbackInfo;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.PackageList;
-import com.android.server.pm.parsing.pkg.PackageImpl;
+
import com.google.common.collect.Range;
import org.junit.Before;
@@ -415,7 +416,7 @@ public class RollbackUnitTest {
private void addPkgWithMinExtVersions(String pkg, int[][] minExtVersions) {
mPackages.add(pkg);
- PackageImpl pkgImpl = new PackageImpl(pkg, "baseCodePath", "codePath", null, false);
+ PackageImpl pkgImpl = new PackageImpl(pkg, "baseCodePath", "codePath", null, false, null);
pkgImpl.setMinExtensionVersions(sparseArrayFrom(minExtVersions));
when(mMockPmi.getPackage(pkg)).thenReturn(pkgImpl);
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 6335b3bfade2..4e1c72af2727 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -46,6 +46,7 @@ android_test {
"testng",
"flag-junit",
"notification_flags_lib",
+ "platform-test-rules",
],
libs: [
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 36d55a48346e..776189eeb7c3 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -211,11 +211,15 @@ import android.os.WorkSource;
import android.permission.PermissionManager;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.platform.test.rule.DeniedDevices;
+import android.platform.test.rule.DeviceProduct;
+import android.platform.test.rule.LimitDevicesRule;
import android.provider.DeviceConfig;
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;
@@ -281,6 +285,7 @@ import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
@@ -313,6 +318,7 @@ import java.util.function.Consumer;
@RunWith(AndroidTestingRunner.class)
@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
@RunWithLooper
+@DeniedDevices(denied = {DeviceProduct.CF_AUTO})
public class NotificationManagerServiceTest extends UiServiceTestCase {
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
private static final String TEST_PACKAGE = "The.name.is.Package.Test.Package";
@@ -331,6 +337,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
private final int mUid = Binder.getCallingUid();
private final @UserIdInt int mUserId = UserHandle.getUserId(mUid);
+ @ClassRule
+ public static final LimitDevicesRule sLimitDevicesRule = new LimitDevicesRule();
+
@Rule
public TestRule compatChangeRule = new PlatformCompatChangeRule();
@@ -627,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);
@@ -654,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()) {
@@ -906,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);
@@ -10082,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 */);
@@ -13201,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/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 646ee3f6d206..1aea56cd8f9f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -80,6 +80,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.notNull;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -265,10 +266,12 @@ public class ZenModeHelperTest extends UiServiceTestCase {
.thenReturn(CUSTOM_PKG_UID);
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
new String[] {pkg});
- ApplicationInfo mockAppInfo = mock(ApplicationInfo.class);
- when(mockAppInfo.loadLabel(any())).thenReturn(CUSTOM_APP_LABEL);
+
+ ApplicationInfo appInfoSpy = spy(new ApplicationInfo());
+ appInfoSpy.icon = ICON_RES_ID;
+ when(appInfoSpy.loadLabel(any())).thenReturn(CUSTOM_APP_LABEL);
when(mPackageManager.getApplicationInfo(eq(CUSTOM_PKG_NAME), anyInt()))
- .thenReturn(mockAppInfo);
+ .thenReturn(appInfoSpy);
mZenModeHelper.mPm = mPackageManager;
mZenModeEventLogger.reset();
@@ -3753,6 +3756,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
rule.zenPolicy = policy;
rule.pkg = ownerPkg;
rule.name = CUSTOM_APP_LABEL;
+ rule.iconResName = ICON_RES_NAME;
+ rule.triggerDescription = mContext.getString(R.string.zen_mode_implicit_trigger_description,
+ CUSTOM_APP_LABEL);
+ rule.type = AutomaticZenRule.TYPE_OTHER;
rule.enabled = true;
return rule;
}
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java b/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java
index 656957c35a5d..159c760992c6 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java
@@ -120,12 +120,12 @@ public class SetSandboxedTrainingDataAllowedTest {
}
@Test
- public void setIsReceiveSandboxedTrainingDataAllowed_currentAndPreinstalledAssistant_setsOp() {
+ public void setShouldReceiveSandboxedTrainingData_currentAndPreinstalledAssistant_setsOp() {
// Set application info so current app is the current and preinstalled assistant.
mApplicationInfo.uid = Process.myUid();
mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
- mVoiceInteractionManagerServiceStub.setIsReceiveSandboxedTrainingDataAllowed(
+ mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
/* allowed= */ true);
verify(mAppOpsManager).setUidMode(mOpIdCaptor.capture(), mUidCaptor.capture(),
@@ -137,7 +137,7 @@ public class SetSandboxedTrainingDataAllowedTest {
}
@Test
- public void setIsReceiveSandboxedTrainingDataAllowed_missingPermission_doesNotSetOp() {
+ public void setShouldReceiveSandboxedTrainingData_missingPermission_doesNotSetOp() {
// Set application info so current app is the current and preinstalled assistant.
mApplicationInfo.uid = Process.myUid();
mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
@@ -146,33 +146,33 @@ public class SetSandboxedTrainingDataAllowedTest {
mPermissionEnforcer.revoke(Manifest.permission.MANAGE_HOTWORD_DETECTION);
assertThrows(SecurityException.class,
- () -> mVoiceInteractionManagerServiceStub.setIsReceiveSandboxedTrainingDataAllowed(
+ () -> mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
/* allowed= */ true));
verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
}
@Test
- public void setIsReceiveSandboxedTrainingDataAllowed_notPreinstalledAssistant_doesNotSetOp() {
+ public void setShouldReceiveSandboxedTrainingData_notPreinstalledAssistant_doesNotSetOp() {
// Set application info so current app is not preinstalled assistant.
mApplicationInfo.uid = Process.myUid();
mApplicationInfo.flags = ApplicationInfo.FLAG_INSTALLED; // Does not contain FLAG_SYSTEM.
assertThrows(SecurityException.class,
- () -> mVoiceInteractionManagerServiceStub.setIsReceiveSandboxedTrainingDataAllowed(
+ () -> mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
/* allowed= */ true));
verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
}
@Test
- public void setIsReceiveSandboxedTrainingDataAllowed_notCurrentAssistant_doesNotSetOp() {
+ public void setShouldReceiveSandboxedTrainingData_notCurrentAssistant_doesNotSetOp() {
// Set application info so current app is not current assistant.
mApplicationInfo.uid = Process.SHELL_UID; // Set current assistant uid to shell UID.
mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
assertThrows(SecurityException.class,
- () -> mVoiceInteractionManagerServiceStub.setIsReceiveSandboxedTrainingDataAllowed(
+ () -> mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
/* allowed= */ true));
verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
index 8d236eda5dc5..0382ca0d9fec 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
@@ -61,6 +61,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase {
META_SHORTCUTS.append(KEYCODE_P, Intent.CATEGORY_APP_MUSIC);
META_SHORTCUTS.append(KEYCODE_S, Intent.CATEGORY_APP_MESSAGING);
}
+ private static final int ANY_DISPLAY_ID = 123;
@Before
public void setUp() {
@@ -96,8 +97,9 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase {
*/
@Test
public void testCtrlSpace() {
- sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_SPACE}, 0);
- mPhoneWindowManager.assertSwitchKeyboardLayout(1);
+ sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_SPACE}, /* duration= */ 0,
+ ANY_DISPLAY_ID);
+ mPhoneWindowManager.assertSwitchKeyboardLayout(/* direction= */ 1, ANY_DISPLAY_ID);
}
/**
@@ -105,8 +107,9 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase {
*/
@Test
public void testCtrlShiftSpace() {
- sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_SHIFT_LEFT, KEYCODE_SPACE}, 0);
- mPhoneWindowManager.assertSwitchKeyboardLayout(-1);
+ sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_SHIFT_LEFT, KEYCODE_SPACE},
+ /* duration= */ 0, ANY_DISPLAY_ID);
+ mPhoneWindowManager.assertSwitchKeyboardLayout(/* direction= */ -1, ANY_DISPLAY_ID);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index 9cdec2588501..157d1627d993 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -114,7 +114,7 @@ class ShortcutKeyTestBase {
}
}
- void sendKeyCombination(int[] keyCodes, long durationMillis, boolean longPress) {
+ void sendKeyCombination(int[] keyCodes, long durationMillis, boolean longPress, int displayId) {
final long downTime = mPhoneWindowManager.getCurrentTime();
final int count = keyCodes.length;
int metaState = 0;
@@ -124,7 +124,7 @@ class ShortcutKeyTestBase {
final KeyEvent event = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode,
0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
0 /*flags*/, InputDevice.SOURCE_KEYBOARD);
- event.setDisplayId(DEFAULT_DISPLAY);
+ event.setDisplayId(displayId);
interceptKey(event);
// The order is important here, metaState could be updated and applied to the next key.
metaState |= MODIFIER.getOrDefault(keyCode, 0);
@@ -142,7 +142,7 @@ class ShortcutKeyTestBase {
KeyEvent.ACTION_DOWN, keyCode, 1 /*repeat*/, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
KeyEvent.FLAG_LONG_PRESS /*flags*/, InputDevice.SOURCE_KEYBOARD);
- nextDownEvent.setDisplayId(DEFAULT_DISPLAY);
+ nextDownEvent.setDisplayId(displayId);
interceptKey(nextDownEvent);
}
}
@@ -153,18 +153,23 @@ class ShortcutKeyTestBase {
final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode,
0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
InputDevice.SOURCE_KEYBOARD);
- upEvent.setDisplayId(DEFAULT_DISPLAY);
+ upEvent.setDisplayId(displayId);
interceptKey(upEvent);
metaState &= ~MODIFIER.getOrDefault(keyCode, 0);
}
}
void sendKeyCombination(int[] keyCodes, long durationMillis) {
- sendKeyCombination(keyCodes, durationMillis, false /* longPress */);
+ sendKeyCombination(keyCodes, durationMillis, false /* longPress */, DEFAULT_DISPLAY);
+ }
+
+ void sendKeyCombination(int[] keyCodes, long durationMillis, int displayId) {
+ sendKeyCombination(keyCodes, durationMillis, false /* longPress */, displayId);
}
void sendLongPressKeyCombination(int[] keyCodes) {
- sendKeyCombination(keyCodes, ViewConfiguration.getLongPressTimeout(), true /* longPress */);
+ sendKeyCombination(keyCodes, ViewConfiguration.getLongPressTimeout(), true /* longPress */,
+ DEFAULT_DISPLAY);
}
void sendKey(int keyCode) {
@@ -172,7 +177,7 @@ class ShortcutKeyTestBase {
}
void sendKey(int keyCode, boolean longPress) {
- sendKeyCombination(new int[]{keyCode}, 0 /*durationMillis*/, longPress);
+ sendKeyCombination(new int[]{keyCode}, 0 /*durationMillis*/, longPress, DEFAULT_DISPLAY);
}
private void interceptKey(KeyEvent keyEvent) {
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index d057226836a3..0678210e1d2f 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -166,12 +166,34 @@ class TestPhoneWindowManager {
@Mock
private PhoneWindowManager.ButtonOverridePermissionChecker mButtonOverridePermissionChecker;
+ @Mock private IBinder mInputToken;
+ @Mock private IBinder mImeTargetWindowToken;
+
private StaticMockitoSession mMockitoSession;
private OffsettableClock mClock = new OffsettableClock();
private TestLooper mTestLooper = new TestLooper(() -> mClock.now());
private HandlerThread mHandlerThread;
private Handler mHandler;
+ private boolean mIsTalkBackEnabled;
+
+ class TestTalkbackShortcutController extends TalkbackShortcutController {
+ TestTalkbackShortcutController(Context context) {
+ super(context);
+ }
+
+ @Override
+ boolean toggleTalkback(int currentUserId) {
+ mIsTalkBackEnabled = !mIsTalkBackEnabled;
+ return mIsTalkBackEnabled;
+ }
+
+ @Override
+ boolean isTalkBackShortcutGestureEnabled() {
+ return true;
+ }
+ }
+
private class TestInjector extends PhoneWindowManager.Injector {
TestInjector(Context context, WindowManagerPolicy.WindowManagerFuncs funcs) {
super(context, funcs, mTestLooper.getLooper());
@@ -197,6 +219,10 @@ class TestPhoneWindowManager {
PhoneWindowManager.ButtonOverridePermissionChecker getButtonOverridePermissionChecker() {
return mButtonOverridePermissionChecker;
}
+
+ TalkbackShortcutController getTalkbackShortcutController() {
+ return new TestTalkbackShortcutController(mContext);
+ }
}
TestPhoneWindowManager(Context context, boolean supportSettingsUpdate) {
@@ -304,6 +330,9 @@ class TestPhoneWindowManager {
doNothing().when(mPhoneWindowManager).finishedWakingUp(anyInt(), anyInt());
doNothing().when(mPhoneWindowManager).lockNow(any());
+ doReturn(mImeTargetWindowToken)
+ .when(mWindowManagerInternal).getTargetWindowTokenFromInputToken(mInputToken);
+
mPhoneWindowManager.init(new TestInjector(mContext, mWindowManagerFuncsImpl));
mPhoneWindowManager.systemReady();
mPhoneWindowManager.systemBooted();
@@ -342,12 +371,12 @@ class TestPhoneWindowManager {
}
long interceptKeyBeforeDispatching(KeyEvent event) {
- return mPhoneWindowManager.interceptKeyBeforeDispatching(null /*focusedToken*/,
- event, FLAG_INTERACTIVE);
+ return mPhoneWindowManager.interceptKeyBeforeDispatching(mInputToken, event,
+ FLAG_INTERACTIVE);
}
void dispatchUnhandledKey(KeyEvent event) {
- mPhoneWindowManager.dispatchUnhandledKey(null /*focusedToken*/, event, FLAG_INTERACTIVE);
+ mPhoneWindowManager.dispatchUnhandledKey(mInputToken, event, FLAG_INTERACTIVE);
}
long getCurrentTime() {
@@ -623,14 +652,16 @@ class TestPhoneWindowManager {
verify(mStatusBarManagerInternal).startAssist(any());
}
- void assertSwitchKeyboardLayout(int direction) {
+ void assertSwitchKeyboardLayout(int direction, int displayId) {
mTestLooper.dispatchAll();
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)) {
- verify(mInputMethodManagerInternal).switchKeyboardLayout(eq(direction));
+ verify(mInputMethodManagerInternal).onSwitchKeyboardLayoutShortcut(eq(direction),
+ eq(displayId), eq(mImeTargetWindowToken));
verify(mWindowManagerFuncsImpl, never()).switchKeyboardLayout(anyInt(), anyInt());
} else {
verify(mWindowManagerFuncsImpl).switchKeyboardLayout(anyInt(), eq(direction));
- verify(mInputMethodManagerInternal, never()).switchKeyboardLayout(anyInt());
+ verify(mInputMethodManagerInternal, never())
+ .onSwitchKeyboardLayoutShortcut(anyInt(), anyInt(), any());
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 65e77dcd4ca9..d4ba3b25178d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -124,7 +124,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
private void verifyOnActivityLaunched(ActivityRecord activity) {
final ArgumentCaptor<Long> idCaptor = ArgumentCaptor.forClass(Long.class);
verifyAsync(mLaunchObserver).onActivityLaunched(idCaptor.capture(),
- eq(activity.mActivityComponent), anyInt());
+ eq(activity.mActivityComponent), anyInt(), anyInt());
final long id = idCaptor.getValue();
setExpectedStartedId(id, activity);
mLastLaunchedIds.put(activity.mActivityComponent, id);
@@ -132,7 +132,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
private void verifyOnActivityLaunchFinished(ActivityRecord activity) {
verifyAsync(mLaunchObserver).onActivityLaunchFinished(eq(mExpectedStartedId),
- eq(activity.mActivityComponent), anyLong());
+ eq(activity.mActivityComponent), anyLong(), anyInt());
}
private void setExpectedStartedId(long id, Object reason) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 7aa46a62b0f1..85c6f9e9b2fe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -123,6 +123,7 @@ import android.app.ICompatCameraControlCallback;
import android.app.PictureInPictureParams;
import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.DestroyActivityItem;
import android.app.servertransaction.PauseActivityItem;
import android.app.servertransaction.WindowStateResizeItem;
@@ -169,6 +170,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import java.util.ArrayList;
+import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -260,8 +262,18 @@ public class ActivityRecordTests extends WindowTestsBase {
final MutableBoolean pauseFound = new MutableBoolean(false);
doAnswer((InvocationOnMock invocationOnMock) -> {
final ClientTransaction transaction = invocationOnMock.getArgument(0);
- if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
- pauseFound.value = true;
+ final List<ClientTransactionItem> items = transaction.getTransactionItems();
+ if (items != null) {
+ for (ClientTransactionItem item : items) {
+ if (item instanceof PauseActivityItem) {
+ pauseFound.value = true;
+ break;
+ }
+ }
+ } else {
+ if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
+ pauseFound.value = true;
+ }
}
return null;
}).when(mClientLifecycleManager).scheduleTransaction(any());
@@ -279,6 +291,8 @@ public class ActivityRecordTests extends WindowTestsBase {
// If the activity is not focusable, it should move to paused.
activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
+ mClientLifecycleManager.dispatchPendingTransactions();
+
assertTrue(activity.isState(PAUSING));
assertTrue(pauseFound.value);
@@ -1239,7 +1253,7 @@ public class ActivityRecordTests extends WindowTestsBase {
}
@Test
- public void testFinishActivityIfPossible_sendResultImmediately() {
+ public void testFinishActivityIfPossible_sendResultImmediately() throws RemoteException {
// Create activity representing the source of the activity result.
final ComponentName sourceComponent = ComponentName.createRelative(
DEFAULT_COMPONENT_PACKAGE_NAME, ".SourceActivity");
@@ -1270,12 +1284,8 @@ public class ActivityRecordTests extends WindowTestsBase {
targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */);
- try {
- verify(mClientLifecycleManager, atLeastOnce()).scheduleTransaction(
- any(ClientTransaction.class));
- } catch (RemoteException ignored) {
- }
-
+ verify(mClientLifecycleManager, atLeastOnce()).scheduleTransactionItem(
+ any(), any(ClientTransactionItem.class));
assertNull(targetActivity.results);
}
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/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java b/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java
index 04aa9815e698..7fdc5fc2cff6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java
@@ -17,13 +17,15 @@
package com.android.server.wm;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.window.flags.Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
@@ -31,12 +33,15 @@ import android.app.IApplicationThread;
import android.app.servertransaction.ActivityLifecycleItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
+import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.filters.SmallTest;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
@@ -47,30 +52,47 @@ import org.mockito.MockitoAnnotations;
* Build/Install/Run:
* atest WmTests:ClientLifecycleManagerTests
*/
+// Suppress GuardedBy warning on unit tests
+@SuppressWarnings("GuardedBy")
@SmallTest
@Presubmit
public class ClientLifecycleManagerTests {
+ @Rule(order = 0)
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Rule(order = 1)
+ public final SystemServicesTestRule mSystemServices = new SystemServicesTestRule();
+
+ @Mock
+ private IBinder mClientBinder;
@Mock
private IApplicationThread mClient;
@Mock
private IApplicationThread.Stub mNonBinderClient;
@Mock
+ private ClientTransaction mTransaction;
+ @Mock
private ClientTransactionItem mTransactionItem;
@Mock
private ActivityLifecycleItem mLifecycleItem;
@Captor
private ArgumentCaptor<ClientTransaction> mTransactionCaptor;
+ private WindowManagerService mWms;
private ClientLifecycleManager mLifecycleManager;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ mWms = mSystemServices.getWindowManagerService();
mLifecycleManager = spy(new ClientLifecycleManager());
+ mLifecycleManager.setWindowManager(mWms);
doReturn(true).when(mLifecycleItem).isActivityLifecycleItem();
+ doReturn(mClientBinder).when(mClient).asBinder();
+ doReturn(mNonBinderClient).when(mNonBinderClient).asBinder();
}
@Test
@@ -92,9 +114,11 @@ public class ClientLifecycleManagerTests {
}
@Test
- public void testScheduleTransactionItem() throws RemoteException {
- doNothing().when(mLifecycleManager).scheduleTransaction(any());
- mLifecycleManager.scheduleTransactionItem(mClient, mTransactionItem);
+ public void testScheduleTransactionItem_notBundle() throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
+ // Use non binder client to get non-recycled ClientTransaction.
+ mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mTransactionItem);
verify(mLifecycleManager).scheduleTransaction(mTransactionCaptor.capture());
ClientTransaction transaction = mTransactionCaptor.getValue();
@@ -104,7 +128,7 @@ public class ClientLifecycleManagerTests {
assertNull(transaction.getTransactionItems());
clearInvocations(mLifecycleManager);
- mLifecycleManager.scheduleTransactionItem(mClient, mLifecycleItem);
+ mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mLifecycleItem);
verify(mLifecycleManager).scheduleTransaction(mTransactionCaptor.capture());
transaction = mTransactionCaptor.getValue();
@@ -113,9 +137,54 @@ public class ClientLifecycleManagerTests {
}
@Test
- public void testScheduleTransactionAndLifecycleItems() throws RemoteException {
- doNothing().when(mLifecycleManager).scheduleTransaction(any());
- mLifecycleManager.scheduleTransactionAndLifecycleItems(mClient, mTransactionItem,
+ public void testScheduleTransactionItem() throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+ spyOn(mWms.mWindowPlacerLocked);
+ doReturn(true).when(mWms.mWindowPlacerLocked).isTraversalScheduled();
+
+ // Use non binder client to get non-recycled ClientTransaction.
+ mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mTransactionItem);
+
+ // When there is traversal scheduled, add transaction items to pending.
+ assertEquals(1, mLifecycleManager.mPendingTransactions.size());
+ ClientTransaction transaction =
+ mLifecycleManager.mPendingTransactions.get(mNonBinderClient);
+ assertEquals(1, transaction.getTransactionItems().size());
+ assertEquals(mTransactionItem, transaction.getTransactionItems().get(0));
+ assertNull(transaction.getCallbacks());
+ assertNull(transaction.getLifecycleStateRequest());
+ verify(mLifecycleManager, never()).scheduleTransaction(any());
+
+ // Add new transaction item to the existing pending.
+ clearInvocations(mLifecycleManager);
+ mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mLifecycleItem);
+
+ assertEquals(1, mLifecycleManager.mPendingTransactions.size());
+ transaction = mLifecycleManager.mPendingTransactions.get(mNonBinderClient);
+ assertEquals(2, transaction.getTransactionItems().size());
+ assertEquals(mTransactionItem, transaction.getTransactionItems().get(0));
+ assertEquals(mLifecycleItem, transaction.getTransactionItems().get(1));
+ assertNull(transaction.getCallbacks());
+ assertNull(transaction.getLifecycleStateRequest());
+ verify(mLifecycleManager, never()).scheduleTransaction(any());
+ }
+
+ @Test
+ public void testScheduleTransactionItemUnlocked() throws RemoteException {
+ // Use non binder client to get non-recycled ClientTransaction.
+ mLifecycleManager.scheduleTransactionItemUnlocked(mNonBinderClient, mTransactionItem);
+
+ // Dispatch immediately.
+ assertTrue(mLifecycleManager.mPendingTransactions.isEmpty());
+ verify(mLifecycleManager).scheduleTransaction(any());
+ }
+
+ @Test
+ public void testScheduleTransactionAndLifecycleItems_notBundle() throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
+ // Use non binder client to get non-recycled ClientTransaction.
+ mLifecycleManager.scheduleTransactionAndLifecycleItems(mNonBinderClient, mTransactionItem,
mLifecycleItem);
verify(mLifecycleManager).scheduleTransaction(mTransactionCaptor.capture());
@@ -124,4 +193,36 @@ public class ClientLifecycleManagerTests {
assertEquals(mTransactionItem, transaction.getCallbacks().get(0));
assertEquals(mLifecycleItem, transaction.getLifecycleStateRequest());
}
+
+ @Test
+ public void testScheduleTransactionAndLifecycleItems() throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+ spyOn(mWms.mWindowPlacerLocked);
+ doReturn(true).when(mWms.mWindowPlacerLocked).isTraversalScheduled();
+
+ // Use non binder client to get non-recycled ClientTransaction.
+ mLifecycleManager.scheduleTransactionAndLifecycleItems(mNonBinderClient, mTransactionItem,
+ mLifecycleItem);
+
+ assertEquals(1, mLifecycleManager.mPendingTransactions.size());
+ final ClientTransaction transaction =
+ mLifecycleManager.mPendingTransactions.get(mNonBinderClient);
+ assertEquals(2, transaction.getTransactionItems().size());
+ assertEquals(mTransactionItem, transaction.getTransactionItems().get(0));
+ assertEquals(mLifecycleItem, transaction.getTransactionItems().get(1));
+ assertNull(transaction.getCallbacks());
+ assertNull(transaction.getLifecycleStateRequest());
+ verify(mLifecycleManager, never()).scheduleTransaction(any());
+ }
+
+ @Test
+ public void testDispatchPendingTransactions() throws RemoteException {
+ mLifecycleManager.mPendingTransactions.put(mClientBinder, mTransaction);
+
+ mLifecycleManager.dispatchPendingTransactions();
+
+ assertTrue(mLifecycleManager.mPendingTransactions.isEmpty());
+ verify(mTransaction).schedule();
+ verify(mTransaction).recycle();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 50fe0425fe9c..1fb7cd8e6e1c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -553,7 +553,7 @@ public class DragDropControllerTests extends WindowTestsBase {
assertTrue(mWm.mInputManager.transferTouchFocus(new InputChannel(),
new InputChannel(), true /* isDragDrop */));
mToken = mTarget.performDrag(TEST_PID, 0, mWindow.mClient,
- flag, surface, 0, 0, 0, 0, 0, data);
+ flag, surface, 0, 0, 0, 0, 0, 0, 0, data);
assertNotNull(mToken);
r.run();
@@ -575,7 +575,7 @@ public class DragDropControllerTests extends WindowTestsBase {
private void startA11yDrag(int flags, ClipData data, Runnable r) {
mToken = mTarget.performDrag(0, 0, mWindow.mClient,
- flags | View.DRAG_FLAG_ACCESSIBILITY_ACTION, null, 0, 0, 0, 0, 0, data);
+ flags | View.DRAG_FLAG_ACCESSIBILITY_ACTION, null, 0, 0, 0, 0, 0, 0, 0, data);
assertNotNull(mToken);
r.run();
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 6e4f13a75625..c902d4597571 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1569,13 +1569,13 @@ public class VoiceInteractionManagerService extends SystemService {
@Override
@EnforcePermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION)
- public void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed) {
- super.setIsReceiveSandboxedTrainingDataAllowed_enforcePermission();
+ public void setShouldReceiveSandboxedTrainingData(boolean allowed) {
+ super.setShouldReceiveSandboxedTrainingData_enforcePermission();
synchronized (this) {
if (mImpl == null) {
throw new IllegalStateException(
- "setIsReceiveSandboxedTrainingDataAllowed without running voice "
+ "setShouldReceiveSandboxedTrainingData without running voice "
+ "interaction service");
}
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/android/telephony/satellite/NtnSignalStrength.java b/telephony/java/android/telephony/satellite/NtnSignalStrength.java
index 16d765455d21..2fec423d1d65 100644
--- a/telephony/java/android/telephony/satellite/NtnSignalStrength.java
+++ b/telephony/java/android/telephony/satellite/NtnSignalStrength.java
@@ -86,6 +86,9 @@ public final class NtnSignalStrength implements Parcelable {
readFromParcel(in);
}
+ /**
+ * Returns notified non-terrestrial network signal strength level.
+ */
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
@NtnSignalStrengthLevel public int getLevel() {
return mLevel;
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 71786b308937..e09bd201f93e 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -34,6 +34,7 @@ import android.os.ICancellationSignal;
import android.os.OutcomeReceiver;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.ServiceSpecificException;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyFrameworkInitializer;
@@ -1919,7 +1920,6 @@ public final class SatelliteManager {
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- @NonNull
public void requestNtnSignalStrength(@NonNull @CallbackExecutor Executor executor,
@NonNull OutcomeReceiver<NtnSignalStrength, SatelliteException> callback) {
Objects.requireNonNull(executor);
@@ -1962,6 +1962,8 @@ public final class SatelliteManager {
/**
* Registers for NTN signal strength changed from satellite modem.
+ * If the registration operation is not successful, a {@link SatelliteException} that contains
+ * {@link SatelliteResult} will be thrown.
*
* <p>
* Note: This API is specifically designed for OEM enabled satellite connectivity only.
@@ -1973,16 +1975,14 @@ public final class SatelliteManager {
* @param executor The executor on which the callback will be called.
* @param callback The callback to handle the NTN signal strength changed event.
*
- * @return The {@link SatelliteResult} result of the operation.
- *
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
+ * @throws SatelliteException if the callback registration operation fails.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- @SatelliteResult public int registerForNtnSignalStrengthChanged(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull NtnSignalStrengthCallback callback) {
+ public void registerForNtnSignalStrengthChanged(@NonNull @CallbackExecutor Executor executor,
+ @NonNull NtnSignalStrengthCallback callback) throws SatelliteException {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
@@ -1999,16 +1999,18 @@ public final class SatelliteManager {
ntnSignalStrength)));
}
};
+ telephony.registerForNtnSignalStrengthChanged(mSubId, internalCallback);
sNtnSignalStrengthCallbackMap.put(callback, internalCallback);
- return telephony.registerForNtnSignalStrengthChanged(mSubId, internalCallback);
} else {
throw new IllegalStateException("Telephony service is null.");
}
+ } catch (ServiceSpecificException ex) {
+ logd("registerForNtnSignalStrengthChanged() registration fails: " + ex.errorCode);
+ throw new SatelliteException(ex.errorCode);
} catch (RemoteException ex) {
loge("registerForNtnSignalStrengthChanged() RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_RESULT_REQUEST_FAILED;
}
/**
@@ -2025,6 +2027,8 @@ public final class SatelliteManager {
* {@link #registerForNtnSignalStrengthChanged(Executor, NtnSignalStrengthCallback)}.
*
* @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalArgumentException if the callback is not valid or has already been
+ * unregistered.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@@ -2041,6 +2045,7 @@ public final class SatelliteManager {
telephony.unregisterForNtnSignalStrengthChanged(mSubId, internalCallback);
} else {
loge("unregisterForNtnSignalStrengthChanged: No internal callback.");
+ throw new IllegalArgumentException("callback is not valid");
}
} else {
throw new IllegalStateException("Telephony service is null.");
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index d7d28a17e7f2..37752d0cecd8 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3101,16 +3101,21 @@ interface ITelephony {
void requestNtnSignalStrength(int subId, in ResultReceiver receiver);
/**
- * Registers for NTN signal strength changed from satellite modem.
+ * Registers for NTN signal strength changed from satellite modem. If the registration operation
+ * is not successful, a {@link SatelliteException} that contains {@link SatelliteResult} will be
+ * thrown.
*
* @param subId The subId of the subscription to request for.
- * @param callback The callback to handle the NTN signal strength changed event.
- *
- * @return The {@link SatelliteResult} result of the operation.
+ * @param callback The callback to handle the NTN signal strength changed event. If the
+ * operation is successful, {@link NtnSignalStrengthCallback#onNtnSignalStrengthChanged(
+ * NtnSignalStrength)} will return an instance of {@link NtnSignalStrength} with a value of
+ * {@link NtnSignalStrength.NtnSignalStrengthLevel} when the signal strength of non-terrestrial
+ * network has changed.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- int registerForNtnSignalStrengthChanged(int subId, in INtnSignalStrengthCallback callback);
+ void registerForNtnSignalStrengthChanged(int subId,
+ in INtnSignalStrengthCallback callback);
/**
* Unregisters for NTN signal strength changed from satellite modem.
@@ -3177,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.
@@ -3191,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 {
diff --git a/tools/aapt2/integration-tests/SymlinkTest/Android.bp b/tools/aapt2/integration-tests/SymlinkTest/Android.bp
index 15a6a207d6d1..6fcdf1c77704 100644
--- a/tools/aapt2/integration-tests/SymlinkTest/Android.bp
+++ b/tools/aapt2/integration-tests/SymlinkTest/Android.bp
@@ -27,4 +27,7 @@ android_test {
name: "AaptSymlinkTest",
sdk_version: "current",
use_resource_processor: false,
+ compile_data: [
+ "targets/*",
+ ],
}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
index 3bcabcb01c5e..d63bff6f4da3 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
@@ -343,6 +343,28 @@ public class Parcel_host {
p.mPos += length;
p.updateSize();
}
+ public static int nativeCompareData(long thisNativePtr, long otherNativePtr) {
+ var a = getInstance(thisNativePtr);
+ var b = getInstance(otherNativePtr);
+ if ((a.mSize == b.mSize) && Arrays.equals(a.mBuffer, b.mBuffer)) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+ public static boolean nativeCompareDataInRange(
+ long ptrA, int offsetA, long ptrB, int offsetB, int length) {
+ var a = getInstance(ptrA);
+ var b = getInstance(ptrB);
+ if (offsetA < 0 || offsetA + length > a.mSize) {
+ throw new IllegalArgumentException();
+ }
+ if (offsetB < 0 || offsetB + length > b.mSize) {
+ throw new IllegalArgumentException();
+ }
+ return Arrays.equals(Arrays.copyOfRange(a.mBuffer, offsetA, offsetA + length),
+ Arrays.copyOfRange(b.mBuffer, offsetB, offsetB + length));
+ }
public static void nativeAppendFrom(
long thisNativePtr, long otherNativePtr, int srcOffset, int length) {
var dst = getInstance(thisNativePtr);