summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TEST_MAPPING6
-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--api/Android.bp2
-rw-r--r--api/api.go136
-rw-r--r--api/api_test.go115
-rw-r--r--api/go.mod2
-rw-r--r--api/go.work2
-rw-r--r--core/api/current.txt7
-rw-r--r--core/api/system-current.txt10
-rw-r--r--core/api/system-lint-baseline.txt2
-rw-r--r--core/api/test-current.txt3
-rw-r--r--core/java/android/accessibilityservice/AccessibilityServiceInfo.java84
-rw-r--r--core/java/android/app/Activity.java4
-rw-r--r--core/java/android/app/ActivityThread.java2
-rw-r--r--core/java/android/app/ApplicationStartInfo.java11
-rw-r--r--core/java/android/app/AutomaticZenRule.java28
-rw-r--r--core/java/android/app/Notification.java85
-rw-r--r--core/java/android/app/PendingIntent.java18
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java2
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java41
-rw-r--r--core/java/android/appwidget/flags.aconfig7
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java5
-rw-r--r--core/java/android/content/Intent.java22
-rw-r--r--core/java/android/content/pm/ILauncherApps.aidl1
-rw-r--r--core/java/android/content/pm/LauncherApps.java23
-rw-r--r--core/java/android/content/pm/PackageInfo.java2
-rw-r--r--core/java/android/content/pm/PackageManager.java9
-rw-r--r--core/java/android/content/pm/multiuser.aconfig7
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionCharacteristics.java2
-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/os/BatteryStats.java4
-rw-r--r--core/java/android/os/ConditionVariable.java1
-rw-r--r--core/java/android/os/Parcel.java2
-rw-r--r--core/java/android/os/flags.aconfig7
-rw-r--r--core/java/android/os/vibrator/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/WindowlessWindowManager.java19
-rw-r--r--core/java/android/view/accessibility/flags/accessibility_flags.aconfig7
-rw-r--r--core/java/android/view/flags/refresh_rate_flags.aconfig8
-rw-r--r--core/java/android/widget/RemoteViews.java55
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig2
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl2
-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/os/BatteryStatsHistory.java13
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHistoryIterator.java1
-rw-r--r--core/java/com/android/internal/os/PowerStats.java2
-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)59
-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/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/com_android_internal_os_ZygoteCommandBuffer.cpp14
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/coretests/src/android/app/AutomaticZenRuleTest.java65
-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/coretests/src/android/widget/RemoteViewsTest.java30
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java10
-rw-r--r--core/tests/utiltests/src/android/util/TimeUtilsTest.java10
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java2
-rw-r--r--libs/WindowManager/Shell/OWNERS2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java31
-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/compatui/UserAspectRatioSettingsWindowManager.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS3
-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.java15
-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/transition/IShellTransitions.aidl10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java23
-rw-r--r--libs/WindowManager/Shell/tests/OWNERS3
-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/compatui/UserAspectRatioSettingsWindowManagerTest.java36
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java4
-rw-r--r--libs/hwui/Android.bp8
-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--packages/CompanionDeviceManager/res/values/strings.xml23
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java25
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java159
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java86
-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/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java51
-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.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java39
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java73
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java52
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java388
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java231
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/Android.bp2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt14
-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.kt6
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt12
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt5
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt4
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt48
-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/Scene.kt24
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt155
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt24
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt7
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt33
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt78
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt16
-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/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/ui/preview/KeyguardRemotePreviewManagerTest.kt40
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt95
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt86
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt16
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt52
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/WorkProfileAutoAddedAfterRestoreTest.kt176
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt12
-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/flashlight/domain/FlashlightMapperTest.kt21
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt19
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt15
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt13
-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/drawable/bouncer_password_text_view_focused_background.xml24
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml1
-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/values-night/colors.xml3
-rw-r--r--packages/SystemUI/res/values/colors.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.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java1
-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/ui/binder/BiometricViewBinder.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt48
-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/FlagDependencies.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java7
-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/KeyguardRepository.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt11
-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/preview/KeyguardRemotePreviewManager.kt103
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogControllerV2.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/RestoreProcessorsModule.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessor.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessor.kt82
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractor.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt32
-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.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt11
-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/flashlight/domain/FlashlightMapper.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt88
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt3
-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/connectivity/AccessPointController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java19
-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/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt14
-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/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/shared/model/BiometricModalitiesTest.kt41
-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/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.java5
-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/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt410
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java64
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt93
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java193
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt109
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java11
-rw-r--r--packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt35
-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/keyguard/data/repository/FakeKeyguardRepository.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt11
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/CustomTileStatePersisterKosmos.kt23
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerFactoryKosmos.kt24
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessorsKosmos.kt29
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt38
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddablesKosmos.kt26
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorKosmos.kt35
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorKosmos.kt52
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorKosmos.kt39
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagRepositoryKosmos.kt21
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt23
-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/settings/FakeUserTracker.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserTrackerKosmos.kt22
-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/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.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--ravenwood/ravenwood-annotation-allowed-classes.txt13
-rw-r--r--services/accessibility/Android.bp3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java18
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java64
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java5
-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/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/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java4
-rw-r--r--services/core/Android.bp3
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java11
-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/BatteryStatsService.java26
-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/app/GameManagerService.java9
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java2
-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.java1
-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/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.java3
-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/AudioPoliciesDeviceRouteController.java15
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java2
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java4
-rw-r--r--services/core/java/com/android/server/notification/flags.aconfig14
-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.java9
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java21
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageAction.java4
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java65
-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.java25
-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.java24
-rw-r--r--services/core/java/com/android/server/pm/PackageArchiver.java59
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerInternalBase.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java29
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageRemovedInfo.java2
-rw-r--r--services/core/java/com/android/server/pm/ReconcilePackageUtils.java35
-rw-r--r--services/core/java/com/android/server/pm/RemovePackageHelper.java48
-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.java2
-rw-r--r--services/core/java/com/android/server/pm/SharedLibrariesImpl.java2
-rw-r--r--services/core/java/com/android/server/pm/SharedUserSetting.java4
-rw-r--r--services/core/java/com/android/server/pm/StorageEventHelper.java5
-rw-r--r--services/core/java/com/android/server/pm/SuspendPackageHelper.java15
-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.java39
-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/SELinuxUtil.java6
-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/power/stats/PowerStatsCollector.java28
-rw-r--r--services/core/java/com/android/server/power/stats/PowerStatsScheduler.java39
-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/vibrator/VibratorControlService.java105
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorControllerHolder.java70
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java7
-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/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/DisplayContent.java9
-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/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/WindowOrganizerController.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java5
-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/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig8
-rw-r--r--services/manifest_services.xml5
-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.java2
-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/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/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.kt66
-rw-r--r--services/tests/powerstatstests/Android.bp23
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java (renamed from services/tests/powerstatstests/src/com/android/server/power/stats/AggregatePowerStatsProcessorTest.java)2
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java7
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java12
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java7
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsSchedulerTest.java55
-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/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.java117
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java14
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java13
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java63
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java72
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java7
-rw-r--r--services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java58
-rw-r--r--services/tests/voiceinteractiontests/Android.bp1
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java180
-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/ClientLifecycleManagerTests.java117
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java4
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java9
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java12
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java5
-rw-r--r--telephony/java/android/telephony/CarrierRestrictionRules.java24
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java10
-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.aidl15
-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/LongArrayMultiStateCounter_host.java9
-rw-r--r--tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java22
540 files changed, 10092 insertions, 3518 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 3409838b5611..117faa203325 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -126,6 +126,12 @@
"exclude-annotation": "org.junit.Ignore"
}
]
+ },
+ {
+ "name": "vts_treble_vintf_framework_test"
+ },
+ {
+ "name": "vts_treble_vintf_vendor_test"
}
],
"postsubmit-ravenwood": [
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/api/Android.bp b/api/Android.bp
index 2b1cfcb82d04..9029d252b470 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -31,12 +31,10 @@ bootstrap_go_package {
"blueprint",
"soong",
"soong-android",
- "soong-bp2build",
"soong-genrule",
"soong-java",
],
srcs: ["api.go"],
- testSrcs: ["api_test.go"],
pluginFor: ["soong_build"],
}
diff --git a/api/api.go b/api/api.go
index 71b1e10d2f47..2668999c572e 100644
--- a/api/api.go
+++ b/api/api.go
@@ -22,7 +22,6 @@ import (
"github.com/google/blueprint/proptools"
"android/soong/android"
- "android/soong/bazel"
"android/soong/genrule"
"android/soong/java"
)
@@ -65,7 +64,6 @@ type CombinedApisProperties struct {
type CombinedApis struct {
android.ModuleBase
- android.BazelModuleBase
properties CombinedApisProperties
}
@@ -115,20 +113,6 @@ type defaultsProps struct {
Previous_api *string
}
-type Bazel_module struct {
- Label *string
- Bp2build_available *bool
-}
-type bazelProperties struct {
- *Bazel_module
-}
-
-var bp2buildNotAvailable = bazelProperties{
- &Bazel_module{
- Bp2build_available: proptools.BoolPtr(false),
- },
-}
-
// Struct to pass parameters for the various merged [current|removed].txt file modules we create.
type MergedTxtDefinition struct {
// "current.txt" or "removed.txt"
@@ -143,8 +127,6 @@ type MergedTxtDefinition struct {
ModuleTag string
// public, system, module-lib or system-server
Scope string
- // True if there is a bp2build definition for this module
- Bp2buildDefined bool
}
func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) {
@@ -178,20 +160,7 @@ func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) {
},
}
props.Visibility = []string{"//visibility:public"}
- bazelProps := bazelProperties{
- &Bazel_module{
- Bp2build_available: proptools.BoolPtr(false),
- },
- }
- if txt.Bp2buildDefined {
- moduleDir := ctx.ModuleDir()
- if moduleDir == android.Bp2BuildTopLevel {
- moduleDir = ""
- }
- label := fmt.Sprintf("//%s:%s", moduleDir, moduleName)
- bazelProps.Label = &label
- }
- ctx.CreateModule(genrule.GenRuleFactory, &props, &bazelProps)
+ ctx.CreateModule(genrule.GenRuleFactory, &props)
}
func createMergedAnnotationsFilegroups(ctx android.LoadHookContext, modules, system_server_modules []string) {
@@ -221,7 +190,7 @@ func createMergedAnnotationsFilegroups(ctx android.LoadHookContext, modules, sys
props := fgProps{}
props.Name = proptools.StringPtr(i.name)
props.Srcs = createSrcs(i.modules, i.tag)
- ctx.CreateModule(android.FileGroupFactory, &props, &bp2buildNotAvailable)
+ ctx.CreateModule(android.FileGroupFactory, &props)
}
}
@@ -315,7 +284,7 @@ func createPublicStubsSourceFilegroup(ctx android.LoadHookContext, modules []str
props.Name = proptools.StringPtr("all-modules-public-stubs-source")
props.Srcs = createSrcs(modules, "{.public.stubs.source}")
props.Visibility = []string{"//frameworks/base"}
- ctx.CreateModule(android.FileGroupFactory, &props, &bp2buildNotAvailable)
+ ctx.CreateModule(android.FileGroupFactory, &props)
}
func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string) {
@@ -323,43 +292,38 @@ func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_
tagSuffix := []string{".api.txt}", ".removed-api.txt}"}
distFilename := []string{"android.txt", "android-removed.txt"}
- bp2BuildDefined := []bool{true, false}
for i, f := range []string{"current.txt", "removed.txt"} {
textFiles = append(textFiles, MergedTxtDefinition{
- TxtFilename: f,
- DistFilename: distFilename[i],
- BaseTxt: ":non-updatable-" + f,
- Modules: bootclasspath,
- ModuleTag: "{.public" + tagSuffix[i],
- Scope: "public",
- Bp2buildDefined: bp2BuildDefined[i],
+ TxtFilename: f,
+ DistFilename: distFilename[i],
+ BaseTxt: ":non-updatable-" + f,
+ Modules: bootclasspath,
+ ModuleTag: "{.public" + tagSuffix[i],
+ Scope: "public",
})
textFiles = append(textFiles, MergedTxtDefinition{
- TxtFilename: f,
- DistFilename: distFilename[i],
- BaseTxt: ":non-updatable-system-" + f,
- Modules: bootclasspath,
- ModuleTag: "{.system" + tagSuffix[i],
- Scope: "system",
- Bp2buildDefined: bp2BuildDefined[i],
+ TxtFilename: f,
+ DistFilename: distFilename[i],
+ BaseTxt: ":non-updatable-system-" + f,
+ Modules: bootclasspath,
+ ModuleTag: "{.system" + tagSuffix[i],
+ Scope: "system",
})
textFiles = append(textFiles, MergedTxtDefinition{
- TxtFilename: f,
- DistFilename: distFilename[i],
- BaseTxt: ":non-updatable-module-lib-" + f,
- Modules: bootclasspath,
- ModuleTag: "{.module-lib" + tagSuffix[i],
- Scope: "module-lib",
- Bp2buildDefined: bp2BuildDefined[i],
+ TxtFilename: f,
+ DistFilename: distFilename[i],
+ BaseTxt: ":non-updatable-module-lib-" + f,
+ Modules: bootclasspath,
+ ModuleTag: "{.module-lib" + tagSuffix[i],
+ Scope: "module-lib",
})
textFiles = append(textFiles, MergedTxtDefinition{
- TxtFilename: f,
- DistFilename: distFilename[i],
- BaseTxt: ":non-updatable-system-server-" + f,
- Modules: system_server_classpath,
- ModuleTag: "{.system-server" + tagSuffix[i],
- Scope: "system-server",
- Bp2buildDefined: bp2BuildDefined[i],
+ TxtFilename: f,
+ DistFilename: distFilename[i],
+ BaseTxt: ":non-updatable-system-server-" + f,
+ Modules: system_server_classpath,
+ ModuleTag: "{.system-server" + tagSuffix[i],
+ Scope: "system-server",
})
}
for _, txt := range textFiles {
@@ -446,55 +410,9 @@ func combinedApisModuleFactory() android.Module {
module.AddProperties(&module.properties)
android.InitAndroidModule(module)
android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) })
- android.InitBazelModule(module)
return module
}
-type bazelCombinedApisAttributes struct {
- Scope bazel.StringAttribute
- Base bazel.LabelAttribute
- Deps bazel.LabelListAttribute
-}
-
-// combined_apis bp2build converter
-func (a *CombinedApis) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
- basePrefix := "non-updatable"
- scopeToSuffix := map[string]string{
- "public": "-current.txt",
- "system": "-system-current.txt",
- "module-lib": "-module-lib-current.txt",
- "system-server": "-system-server-current.txt",
- }
-
- for scopeName, suffix := range scopeToSuffix {
- name := a.Name() + suffix
-
- var scope bazel.StringAttribute
- scope.SetValue(scopeName)
-
- var base bazel.LabelAttribute
- base.SetValue(android.BazelLabelForModuleDepSingle(ctx, basePrefix+suffix))
-
- var deps bazel.LabelListAttribute
- classpath := a.properties.Bootclasspath
- if scopeName == "system-server" {
- classpath = a.properties.System_server_classpath
- }
- deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, classpath))
-
- attrs := bazelCombinedApisAttributes{
- Scope: scope,
- Base: base,
- Deps: deps,
- }
- props := bazel.BazelTargetModuleProperties{
- Rule_class: "merged_txts",
- Bzl_load_location: "//build/bazel/rules/java:merged_txts.bzl",
- }
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, &attrs)
- }
-}
-
// Various utility methods below.
// Creates an array of ":<m><tag>" for each m in <modules>.
diff --git a/api/api_test.go b/api/api_test.go
deleted file mode 100644
index 70f2162348ad..000000000000
--- a/api/api_test.go
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (C) 2023 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package api
-
-import (
- "testing"
-
- "android/soong/android"
- "android/soong/bp2build"
- "android/soong/java"
-)
-
-func runCombinedApisTestCaseWithRegistrationCtxFunc(t *testing.T, tc bp2build.Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
- t.Helper()
- (&tc).ModuleTypeUnderTest = "combined_apis"
- (&tc).ModuleTypeUnderTestFactory = combinedApisModuleFactory
- bp2build.RunBp2BuildTestCase(t, registrationCtxFunc, tc)
-}
-
-func runCombinedApisTestCase(t *testing.T, tc bp2build.Bp2buildTestCase) {
- t.Helper()
- runCombinedApisTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("java_defaults", java.DefaultsFactory)
- ctx.RegisterModuleType("java_sdk_library", java.SdkLibraryFactory)
- ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
- })
-}
-
-func TestCombinedApisGeneral(t *testing.T) {
- runCombinedApisTestCase(t, bp2build.Bp2buildTestCase{
- Description: "combined_apis, general case",
- Blueprint: `combined_apis {
- name: "foo",
- bootclasspath: ["bcp"],
- system_server_classpath: ["ssc"],
-}
-
-java_sdk_library {
- name: "bcp",
- srcs: ["a.java", "b.java"],
- shared_library: false,
-}
-java_sdk_library {
- name: "ssc",
- srcs: ["a.java", "b.java"],
- shared_library: false,
-}
-filegroup {
- name: "non-updatable-current.txt",
- srcs: ["current.txt"],
-}
-filegroup {
- name: "non-updatable-system-current.txt",
- srcs: ["system-current.txt"],
-}
-filegroup {
- name: "non-updatable-module-lib-current.txt",
- srcs: ["system-removed.txt"],
-}
-filegroup {
- name: "non-updatable-system-server-current.txt",
- srcs: ["system-lint-baseline.txt"],
-}
-`,
- Filesystem: map[string]string{
- "a/Android.bp": `
- java_defaults {
- name: "android.jar_defaults",
- }
- `,
- "api/current.txt": "",
- "api/removed.txt": "",
- "api/system-current.txt": "",
- "api/system-removed.txt": "",
- "api/test-current.txt": "",
- "api/test-removed.txt": "",
- },
- StubbedBuildDefinitions: []string{"bcp", "ssc", "non-updatable-current.txt", "non-updatable-system-current.txt", "non-updatable-module-lib-current.txt", "non-updatable-system-server-current.txt"},
- ExpectedHandcraftedModules: []string{"foo-current.txt", "foo-system-current.txt", "foo-module-lib-current.txt", "foo-system-server-current.txt"},
- ExpectedBazelTargets: []string{
- bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-current.txt", bp2build.AttrNameToString{
- "scope": `"public"`,
- "base": `":non-updatable-current.txt"`,
- "deps": `[":bcp"]`,
- }),
- bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-system-current.txt", bp2build.AttrNameToString{
- "scope": `"system"`,
- "base": `":non-updatable-system-current.txt"`,
- "deps": `[":bcp"]`,
- }),
- bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-module-lib-current.txt", bp2build.AttrNameToString{
- "scope": `"module-lib"`,
- "base": `":non-updatable-module-lib-current.txt"`,
- "deps": `[":bcp"]`,
- }),
- bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-system-server-current.txt", bp2build.AttrNameToString{
- "scope": `"system-server"`,
- "base": `":non-updatable-system-server-current.txt"`,
- "deps": `[":ssc"]`,
- }),
- },
- })
-}
diff --git a/api/go.mod b/api/go.mod
index f8bb1c01cd96..445a6f4a5ec6 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -6,7 +6,5 @@ require (
android/soong v0.0.0
github.com/google/blueprint v0.0.0
google.golang.org/protobuf v0.0.0
- prebuilts/bazel/common/proto/analysis_v2 v0.0.0
- prebuilts/bazel/common/proto/build v0.0.0
go.starlark.net v0.0.0
)
diff --git a/api/go.work b/api/go.work
index aa2d2b1cb461..edd002e7efba 100644
--- a/api/go.work
+++ b/api/go.work
@@ -13,7 +13,5 @@ replace (
google.golang.org/protobuf v0.0.0 => ../../../external/golang-protobuf
github.com/google/blueprint v0.0.0 => ../../../build/blueprint
github.com/google/go-cmp v0.0.0 => ../../../external/go-cmp
- prebuilts/bazel/common/proto/analysis_v2 v0.0.0 => ../../../prebuilts/bazel/common/proto/analysis_v2
- prebuilts/bazel/common/proto/build v0.0.0 => ../../../prebuilts/bazel/common/proto/build
go.starlark.net v0.0.0 => ../../../external/starlark-go
)
diff --git a/core/api/current.txt b/core/api/current.txt
index 83e3fabe475b..7f261d450b42 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5285,9 +5285,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 {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9f56933865db..e92564b5d7c2 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
@@ -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();
@@ -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/api/test-current.txt b/core/api/test-current.txt
index 39f2737dc880..a3cd3dc87db3 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2,6 +2,7 @@
package android {
public static final class Manifest.permission {
+ field @FlaggedApi("com.android.server.accessibility.motion_event_observing") public static final String ACCESSIBILITY_MOTION_EVENT_OBSERVING = "android.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING";
field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY";
@@ -99,6 +100,8 @@ package android.accessibilityservice {
public class AccessibilityServiceInfo implements android.os.Parcelable {
method @NonNull public android.content.ComponentName getComponentName();
+ method @FlaggedApi("android.view.accessibility.motion_event_observing") public int getObservedMotionEventSources();
+ method @FlaggedApi("android.view.accessibility.motion_event_observing") public void setObservedMotionEventSources(int);
}
}
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 8ad6ea207665..fc342fa3431a 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -20,6 +20,7 @@ import static android.accessibilityservice.util.AccessibilityUtils.getFilteredHt
import static android.accessibilityservice.util.AccessibilityUtils.loadSafeAnimatedImage;
import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -53,6 +54,7 @@ import android.view.InputDevice;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.Flags;
import com.android.internal.R;
import com.android.internal.compat.IPlatformCompat;
@@ -630,7 +632,8 @@ public class AccessibilityServiceInfo implements Parcelable {
InputDevice.SOURCE_TOUCH_NAVIGATION,
InputDevice.SOURCE_ROTARY_ENCODER,
InputDevice.SOURCE_JOYSTICK,
- InputDevice.SOURCE_SENSOR
+ InputDevice.SOURCE_SENSOR,
+ InputDevice.SOURCE_TOUCHSCREEN
})
@Retention(RetentionPolicy.SOURCE)
public @interface MotionEventSources {}
@@ -642,6 +645,8 @@ public class AccessibilityServiceInfo implements Parcelable {
@MotionEventSources
private int mMotionEventSources = 0;
+ private int mObservedMotionEventSources = 0;
+
/**
* Creates a new instance.
*/
@@ -817,6 +822,9 @@ public class AccessibilityServiceInfo implements Parcelable {
mInteractiveUiTimeout = other.mInteractiveUiTimeout;
flags = other.flags;
mMotionEventSources = other.mMotionEventSources;
+ if (Flags.motionEventObserving()) {
+ setObservedMotionEventSources(other.mObservedMotionEventSources);
+ }
// NOTE: Ensure that only properties that are safe to be modified by the service itself
// are included here (regardless of hidden setters, etc.).
}
@@ -1024,16 +1032,75 @@ public class AccessibilityServiceInfo implements Parcelable {
*/
public void setMotionEventSources(@MotionEventSources int motionEventSources) {
mMotionEventSources = motionEventSources;
+ mObservedMotionEventSources = 0;
+ }
+
+ /**
+ * Sets the bit mask of {@link android.view.InputDevice} sources that the accessibility service
+ * wants to observe generic {@link android.view.MotionEvent}s from if it has already requested
+ * to listen to them using {@link #setMotionEventSources(int)}. Events from these sources will
+ * be sent to the rest of the input pipeline without being consumed by accessibility services.
+ * This service will still be able to see them.
+ *
+ * <p><strong>Note:</strong> you will need to call this function every time you call {@link
+ * #setMotionEventSources(int)}. Calling {@link #setMotionEventSources(int)} clears the list of
+ * observed motion event sources for this service.
+ *
+ * <p><strong>Note:</strong> {@link android.view.InputDevice} sources contain source class bits
+ * that complicate bitwise flag removal operations. To remove a specific source you should
+ * rebuild the entire value using bitwise OR operations on the individual source constants.
+ *
+ * <p>Including an {@link android.view.InputDevice} source that does not send {@link
+ * android.view.MotionEvent}s is effectively a no-op for that source, since you will not receive
+ * any events from that source.
+ *
+ * <p><strong>Note:</strong> Calling this function with a source that has not been listened to
+ * using {@link #setMotionEventSources(int)} will throw an exception.
+ *
+ * @see AccessibilityService#onMotionEvent
+ * @see #MotionEventSources
+ * @see #setMotionEventSources(int)
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_MOTION_EVENT_OBSERVING)
+ @TestApi
+ public void setObservedMotionEventSources(int observedMotionEventSources) {
+ // Confirm that any sources requested here have already been requested for listening.
+ if ((observedMotionEventSources & ~mMotionEventSources) != 0) {
+ String message =
+ String.format(
+ "Requested motion event sources for listening = 0x%x but requested"
+ + " motion event sources for observing = 0x%x.",
+ mMotionEventSources, observedMotionEventSources);
+ throw new IllegalArgumentException(message);
+ }
+ mObservedMotionEventSources = observedMotionEventSources;
+ }
+
+ /**
+ * Returns the bit mask of {@link android.view.InputDevice} sources that the accessibility
+ * service wants to observe generic {@link android.view.MotionEvent}s from if it has already
+ * requested to listen to them using {@link #setMotionEventSources(int)}. Events from these
+ * sources will be sent to the rest of the input pipeline without being consumed by
+ * accessibility services. This service will still be able to see them.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_MOTION_EVENT_OBSERVING)
+ @MotionEventSources
+ @TestApi
+ public int getObservedMotionEventSources() {
+ return mObservedMotionEventSources;
}
/**
* The localized summary of the accessibility service.
- * <p>
- * <strong>Statically set from
- * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
- * </p>
- * @return The localized summary if available, and {@code null} if a summary
- * has not been provided.
+ *
+ * <p><strong>Statically set from {@link AccessibilityService#SERVICE_META_DATA
+ * meta-data}.</strong>
+ *
+ * @return The localized summary if available, and {@code null} if a summary has not been
+ * provided.
*/
public CharSequence loadSummary(PackageManager packageManager) {
if (mSummaryResId == 0) {
@@ -1260,6 +1327,7 @@ public class AccessibilityServiceInfo implements Parcelable {
parcel.writeString(mTileServiceName);
parcel.writeInt(mIntroResId);
parcel.writeInt(mMotionEventSources);
+ parcel.writeInt(mObservedMotionEventSources);
}
private void initFromParcel(Parcel parcel) {
@@ -1285,6 +1353,8 @@ public class AccessibilityServiceInfo implements Parcelable {
mTileServiceName = parcel.readString();
mIntroResId = parcel.readInt();
mMotionEventSources = parcel.readInt();
+ // use the setter here because it throws an exception for invalid values.
+ setObservedMotionEventSources(parcel.readInt());
}
@Override
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ffed40538702..4a9fa9e63bf9 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6884,8 +6884,8 @@ public class Activity extends ContextThemeWrapper
* application package was involved.
*
* <p>If called while inside the handling of {@link #onNewIntent}, this function will
- * return the referrer that submitted that new intent to the activity. Otherwise, it
- * always returns the referrer of the original Intent.</p>
+ * return the referrer that submitted that new intent to the activity only after
+ * {@link #setIntent(Intent)} is called with the provided intent.</p>
*
* <p>Note that this is <em>not</em> a security feature -- you can not trust the
* referrer information, applications can spoof it.</p>
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/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..53a21cdd78c9 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;
@@ -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/Notification.java b/core/java/android/app/Notification.java
index a510c7704751..013bcddbb7f3 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2205,9 +2205,6 @@ public class Notification implements Parcelable
private void visitUris(@NonNull Consumer<Uri> visitor) {
visitIconUri(visitor, getIcon());
- if (actionIntent != null) {
- actionIntent.visitUris(visitor);
- }
}
@Override
@@ -2901,21 +2898,6 @@ public class Notification implements Parcelable
}
}
- // allPendingIntents should contain all associated intents after parcelling, but it may also
- // contain intents added by the app to extras for their own purposes. We only care about
- // checking the intents known and used by system_server, to avoid the confused deputy issue.
- List<PendingIntent> pendingIntents = Arrays.asList(contentIntent, deleteIntent,
- fullScreenIntent);
- for (PendingIntent intent : pendingIntents) {
- if (intent != null) {
- intent.visitUris(visitor);
- }
- }
-
- if (mBubbleMetadata != null) {
- mBubbleMetadata.visitUris(visitor);
- }
-
if (extras != null) {
visitIconUri(visitor, extras.getParcelable(EXTRA_LARGE_ICON_BIG, Icon.class));
visitIconUri(visitor, extras.getParcelable(EXTRA_PICTURE_ICON, Icon.class));
@@ -2987,28 +2969,15 @@ public class Notification implements Parcelable
callPerson.visitUris(visitor);
}
visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON, Icon.class));
+ }
- // Extras for MediaStyle.
- PendingIntent deviceIntent = extras.getParcelable(EXTRA_MEDIA_REMOTE_INTENT,
- PendingIntent.class);
- if (deviceIntent != null) {
- deviceIntent.visitUris(visitor);
- }
-
- if (extras.containsKey(WearableExtender.EXTRA_WEARABLE_EXTENSIONS)) {
- WearableExtender extender = new WearableExtender(this);
- extender.visitUris(visitor);
- }
-
- if (extras.containsKey(TvExtender.EXTRA_TV_EXTENDER)) {
- TvExtender extender = new TvExtender(this);
- extender.visitUris(visitor);
- }
+ if (mBubbleMetadata != null) {
+ visitIconUri(visitor, mBubbleMetadata.getIcon());
+ }
- if (extras.containsKey(CarExtender.EXTRA_CAR_EXTENDER)) {
- CarExtender extender = new CarExtender(this);
- extender.visitUris(visitor);
- }
+ if (extras != null && extras.containsKey(WearableExtender.EXTRA_WEARABLE_EXTENSIONS)) {
+ WearableExtender extender = new WearableExtender(this);
+ extender.visitUris(visitor);
}
}
@@ -10589,16 +10558,6 @@ public class Notification implements Parcelable
}
}
- private void visitUris(@NonNull Consumer<Uri> visitor) {
- visitIconUri(visitor, getIcon());
- if (mPendingIntent != null) {
- mPendingIntent.visitUris(visitor);
- }
- if (mDeleteIntent != null) {
- mDeleteIntent.visitUris(visitor);
- }
- }
-
/**
* Builder to construct a {@link BubbleMetadata} object.
*/
@@ -11797,9 +11756,6 @@ public class Notification implements Parcelable
}
private void visitUris(@NonNull Consumer<Uri> visitor) {
- if (mDisplayIntent != null) {
- mDisplayIntent.visitUris(visitor);
- }
for (Action action : mActions) {
action.visitUris(visitor);
}
@@ -11952,19 +11908,12 @@ public class Notification implements Parcelable
/**
* Returns the unread conversation conveyed by this notification.
- *
* @see #setUnreadConversation(UnreadConversation)
*/
public UnreadConversation getUnreadConversation() {
return mUnreadConversation;
}
- private void visitUris(@NonNull Consumer<Uri> visitor) {
- if (mUnreadConversation != null) {
- mUnreadConversation.visitUris(visitor);
- }
- }
-
/**
* A class which holds the unread messages from a conversation.
*/
@@ -12116,16 +12065,7 @@ public class Notification implements Parcelable
onRead,
participants, b.getLong(KEY_TIMESTAMP));
}
-
- private void visitUris(@NonNull Consumer<Uri> visitor) {
- if (mReadPendingIntent != null) {
- mReadPendingIntent.visitUris(visitor);
- }
- if (mReplyPendingIntent != null) {
- mReplyPendingIntent.visitUris(visitor);
- }
- }
- }
+ };
/**
* Builder class for {@link CarExtender.UnreadConversation} objects.
@@ -12448,15 +12388,6 @@ public class Notification implements Parcelable
public boolean isSuppressShowOverApps() {
return mSuppressShowOverApps;
}
-
- private void visitUris(@NonNull Consumer<Uri> visitor) {
- if (mContentIntent != null) {
- mContentIntent.visitUris(visitor);
- }
- if (mDeleteIntent != null) {
- mDeleteIntent.visitUris(visitor);
- }
- }
}
/**
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 0261f0a02174..62209b0fd27d 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -44,8 +44,6 @@ import android.content.IntentSender;
import android.content.pm.PackageManager.ResolveInfoFlagsBits;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -71,7 +69,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
-import java.util.function.Consumer;
/**
* A description of an Intent and target action to perform with it. Instances
@@ -1463,21 +1460,6 @@ public final class PendingIntent implements Parcelable {
return sb.toString();
}
- /**
- * See {@link Intent#visitUris(Consumer)}.
- *
- * @hide
- */
- public void visitUris(@NonNull Consumer<Uri> visitor) {
- if (android.app.Flags.visitRiskyUris()) {
- Intent intent = Binder.withCleanCallingIdentity(this::getIntent);
-
- if (intent != null) {
- intent.visitUris(visitor);
- }
- }
- }
-
/** @hide */
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 90a265937082..4a6349b1b02f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9381,7 +9381,7 @@ public class DevicePolicyManager {
@Deprecated
@SystemApi
@RequiresPermission(MANAGE_DEVICE_ADMINS)
- public boolean setActiveProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName)
+ public boolean setActiveProfileOwner(@NonNull ComponentName admin, String ownerName)
throws IllegalArgumentException {
throwIfParentInstance("setActiveProfileOwner");
if (mService != null) {
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/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index e4a03c596254..d5b5f40a6980 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -37,6 +37,7 @@ import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
@@ -709,7 +710,9 @@ public final class CompanionDeviceManager {
IntentSender intentSender = mService
.requestNotificationAccess(component, mContext.getUserId())
.getIntentSender();
- mContext.startIntentSender(intentSender, null, 0, 0, 0);
+ mContext.startIntentSender(intentSender, null, 0, 0, 0,
+ ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (IntentSender.SendIntentException e) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 183b9b0000d2..7af0be3b3e75 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -101,7 +101,6 @@ import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
-import java.util.function.Consumer;
/**
* An intent is an abstract description of an operation to be performed. It
@@ -8148,27 +8147,6 @@ public class Intent implements Parcelable, Cloneable {
}
}
- /**
- * Note all {@link Uri} that are referenced internally, with the expectation that Uri permission
- * grants will need to be issued to ensure the recipient of this object is able to render its
- * contents.
- * See b/281044385 for more context and examples about what happens when this isn't done
- * correctly.
- *
- * @hide
- */
- public void visitUris(@NonNull Consumer<Uri> visitor) {
- if (android.app.Flags.visitRiskyUris()) {
- visitor.accept(mData);
- if (mSelector != null) {
- mSelector.visitUris(visitor);
- }
- if (mOriginalIntent != null) {
- mOriginalIntent.visitUris(visitor);
- }
- }
- }
-
public static Intent getIntentOld(String uri) throws URISyntaxException {
Intent intent = getIntentOld(uri, 0);
intent.mLocalFlags |= LOCAL_FLAG_FROM_URI;
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index e9f419e9a8ce..6f7299aa8e31 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -64,6 +64,7 @@ interface ILauncherApps {
PendingIntent getActivityLaunchIntent(String callingPackage, in ComponentName component,
in UserHandle user);
LauncherUserInfo getLauncherUserInfo(in UserHandle user);
+ List<String> getPreInstalledSystemPackages(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/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 0cd4358b2c91..ccc8f0956865 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -800,6 +800,29 @@ public class LauncherApps {
}
/**
+ * 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/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e2243292ab8d..a5d16f2f6be1 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;
@@ -6302,6 +6300,11 @@ public abstract class PackageManager {
/**
* Check whether a particular package has been granted a particular
* permission.
+ * <p>
+ * <strong>Note: </strong>This API returns the underlying permission state
+ * as-is and is mostly intended for permission managing system apps. To
+ * perform an access check for a certain app, please use the
+ * {@link Context#checkPermission} APIs instead.
*
* @param permName The name of the permission you are checking for.
* @param packageName The name of the package you are checking against.
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 6c6b33b8d716..57025c25f97b 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -49,3 +49,10 @@ flag {
description: "Add support to unlock the private space using biometrics"
bug: "312184187"
}
+
+flag {
+ name: "support_autolock_for_private_space"
+ namespace: "profile_experiences"
+ description: "Add support to lock private space automatically after a time period"
+ bug: "303201022"
+}
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 8196bf505e02..20b09326e9c0 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -40,7 +40,6 @@ import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
-import android.util.FeatureFlagUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
@@ -722,6 +721,7 @@ public final class CameraExtensionCharacteristics {
switch(format) {
case ImageFormat.YUV_420_888:
case ImageFormat.JPEG:
+ case ImageFormat.JPEG_R:
break;
default:
throw new IllegalArgumentException("Unsupported format: " + format);
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/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 16ffaef03121..10a8022df0ea 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1657,6 +1657,7 @@ public abstract class BatteryStats {
*/
public abstract CpuScalingPolicies getCpuScalingPolicies();
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public final static class HistoryTag {
public static final int HISTORY_TAG_POOL_OVERFLOW = -1;
@@ -1713,6 +1714,7 @@ public abstract class BatteryStats {
* Optional detailed information that can go into a history step. This is typically
* generated each time the battery level changes.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public final static class HistoryStepDetails {
// Time (in 1/100 second) spent in user space and the kernel since the last step.
public int userTime;
@@ -1797,6 +1799,7 @@ public abstract class BatteryStats {
/**
* An extension to the history item describing a proc state change for a UID.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static final class ProcessStateChange {
public int uid;
public @BatteryConsumer.ProcessState int processState;
@@ -1850,6 +1853,7 @@ public abstract class BatteryStats {
/**
* Battery history record.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static final class HistoryItem {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public HistoryItem next;
diff --git a/core/java/android/os/ConditionVariable.java b/core/java/android/os/ConditionVariable.java
index a13eaa6f19bf..b5ed53bf0e5e 100644
--- a/core/java/android/os/ConditionVariable.java
+++ b/core/java/android/os/ConditionVariable.java
@@ -29,6 +29,7 @@ package android.os;
* This class uses itself as the object to wait on, so if you wait()
* or notify() on a ConditionVariable, the results are undefined.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ConditionVariable
{
private volatile boolean mCondition;
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/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index 69d86a6604ad..437668c9a7de 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -44,3 +44,10 @@ flag {
description: "Enables the independent keyboard vibration settings feature"
bug: "289107579"
}
+
+flag {
+ namespace: "haptics"
+ name: "adaptive_haptics_enabled"
+ description: "Enables the adaptive haptics feature"
+ bug: "305961689"
+}
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/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/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index e057660961f6..0cc19fb70fbc 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -59,6 +59,13 @@ flag {
}
flag {
+ name: "motion_event_observing"
+ namespace: "accessibility"
+ description: "Allows accessibility services to intercept but not consume motion events from specified sources."
+ bug: "297595990"
+}
+
+flag {
namespace: "accessibility"
name: "granular_scrolling"
description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen"
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 a31a610ab523..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;
@@ -1015,11 +1014,6 @@ public class RemoteViews implements Parcelable, Filter {
public int getActionTag() {
return SET_PENDING_INTENT_TEMPLATE_TAG;
}
-
- @Override
- public void visitUris(@NonNull Consumer<Uri> visitor) {
- mPendingIntentTemplate.visitUris(visitor);
- }
}
/**
@@ -1434,7 +1428,9 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public void visitUris(@NonNull Consumer<Uri> visitor) {
- mIntent.visitUris(visitor);
+ // TODO(b/281044385): Maybe visit intent URIs. This may require adding a dedicated
+ // visitUris method in the Intent class, since it can contain other intents. Otherwise,
+ // the basic thing to do here would be just visitor.accept(intent.getData()).
}
}
@@ -1514,7 +1510,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public void visitUris(@NonNull Consumer<Uri> visitor) {
- mResponse.visitUris(visitor);
+ // TODO(b/281044385): Maybe visit intent URIs in the RemoteResponse.
}
}
@@ -1563,11 +1559,6 @@ public class RemoteViews implements Parcelable, Filter {
public int getActionTag() {
return SET_ON_STYLUS_HANDWRITING_RESPONSE_TAG;
}
-
- @Override
- public void visitUris(@NonNull Consumer<Uri> visitor) {
- mPendingIntent.visitUris(visitor);
- }
}
/**
@@ -1641,7 +1632,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public void visitUris(@NonNull Consumer<Uri> visitor) {
- mResponse.visitUris(visitor);
+ // TODO(b/281044385): Maybe visit intent URIs in the RemoteResponse.
}
}
@@ -2202,10 +2193,6 @@ public class RemoteViews implements Parcelable, Filter {
final Icon icon = (Icon) getParameterValue(null);
if (icon != null) visitIconUri(icon, visitor);
break;
- case INTENT:
- final Intent intent = (Intent) getParameterValue(null);
- if (intent != null) intent.visitUris(visitor);
- break;
// TODO(b/281044385): Should we do anything about type BUNDLE?
}
}
@@ -4962,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;
}
/**
@@ -6995,20 +6972,6 @@ public class RemoteViews implements Parcelable, Filter {
mElementNames = parcel.createStringArrayList();
}
- /**
- * See {@link RemoteViews#visitUris(Consumer)}.
- *
- * @hide
- */
- public void visitUris(@NonNull Consumer<Uri> visitor) {
- if (mPendingIntent != null) {
- mPendingIntent.visitUris(visitor);
- }
- if (mFillIntent != null) {
- mFillIntent.visitUris(visitor);
- }
- }
-
private void handleViewInteraction(
View v,
InteractionHandler handler) {
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 7f65c52d01b8..07beb114898d 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -16,7 +16,7 @@ flag {
flag {
name: "defer_display_updates"
- namespace: "window_manager"
+ namespace: "windowing_frontend"
description: "Feature flag for deferring DisplayManager updates to WindowManager if Shell transition is running"
bug: "259220649"
is_fixed_read_only: true
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/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/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 7d78f299c625..0be98040af73 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -72,6 +72,7 @@ import java.util.concurrent.locks.ReentrantLock;
* All interfaces in BatteryStatsHistory should only be called by BatteryStatsImpl and protected by
* locks on BatteryStatsImpl object.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class BatteryStatsHistory {
private static final boolean DEBUG = false;
private static final String TAG = "BatteryStatsHistory";
@@ -259,6 +260,7 @@ public class BatteryStatsHistory {
* until the first change occurs.
*/
@VisibleForTesting
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static class TraceDelegate {
// Note: certain tests currently run as platform_app which is not allowed
// to set debug system properties. To ensure that system properties are set
@@ -391,10 +393,18 @@ public class BatteryStatsHistory {
public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize,
HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock,
MonotonicClock monotonicClock) {
+ this(maxHistoryFiles, maxHistoryBufferSize, stepDetailsCalculator, clock, monotonicClock,
+ new TraceDelegate());
+ }
+
+ @VisibleForTesting
+ public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize,
+ HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock,
+ MonotonicClock monotonicClock, TraceDelegate traceDelegate) {
mMaxHistoryFiles = maxHistoryFiles;
mMaxHistoryBufferSize = maxHistoryBufferSize;
mStepDetailsCalculator = stepDetailsCalculator;
- mTracer = new TraceDelegate();
+ mTracer = traceDelegate;
mClock = clock;
mMonotonicClock = monotonicClock;
@@ -2096,6 +2106,7 @@ public class BatteryStatsHistory {
* fewer bytes. It is a bit more expensive than just writing the long into the parcel,
* but at scale saves a lot of storage and allows recording of longer battery history.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static final class VarintParceler {
/**
* Writes an array of longs into Parcel using the varint format, see
diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
index 6bd5898b1637..2dffe15dc4be 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
@@ -28,6 +28,7 @@ import java.util.Iterator;
/**
* An iterator for {@link BatteryStats.HistoryItem}'s.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.HistoryItem>,
AutoCloseable {
private static final boolean DEBUG = false;
diff --git a/core/java/com/android/internal/os/PowerStats.java b/core/java/com/android/internal/os/PowerStats.java
index 1a7efac82278..56263fb924ea 100644
--- a/core/java/com/android/internal/os/PowerStats.java
+++ b/core/java/com/android/internal/os/PowerStats.java
@@ -41,6 +41,7 @@ import java.util.Objects;
* Container for power stats, acquired by various PowerStatsCollector classes. See subclasses for
* details.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class PowerStats {
private static final String TAG = "PowerStats";
@@ -67,6 +68,7 @@ public final class PowerStats {
* This descriptor is used for storing PowerStats and can also be used by power models
* to adjust the algorithm in accordance with the stats available on the device.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static class Descriptor {
public static final String XML_TAG_DESCRIPTOR = "descriptor";
private static final String XML_ATTR_ID = "id";
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..f7e1f7293ac6 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
@@ -2694,12 +2693,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 +2753,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 +3092,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/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/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/AndroidManifest.xml b/core/res/AndroidManifest.xml
index dd93586c340b..c6a241f2fa62 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4806,6 +4806,13 @@
<permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME"
android:protectionLevel="signature" />
+ <!-- @FlaggedApi("com.android.server.accessibility.motion_event_observing")
+ @hide
+ @TestApi
+ Allows an accessibility service to observe motion events without consuming them. -->
+ <permission android:name="android.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING"
+ android:protectionLevel="signature" />
+
<!-- @hide Allows an application to collect frame statistics -->
<permission android:name="android.permission.FRAME_STATS"
android:protectionLevel="signature" />
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..fd6158d02b8f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2586,6 +2586,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..d629f6a8c57c 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,60 @@ 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 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/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 15c90474c017..c8ea3742b3aa 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -34,6 +34,9 @@ import android.app.PendingIntent;
import android.appwidget.AppWidgetHostView;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.AsyncTask;
@@ -834,33 +837,6 @@ public class RemoteViewsTest {
}
@Test
- public void visitUris_intents() {
- RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
-
- Uri fillIntentUri = Uri.parse("content://intent/fill");
- views.setOnCheckedChangeResponse(
- R.id.layout,
- RemoteViews.RemoteResponse.fromFillInIntent(new Intent("action", fillIntentUri)));
-
- Uri pendingIntentUri = Uri.parse("content://intent/pending");
- PendingIntent pendingIntent = getPendingIntentWithUri(pendingIntentUri);
- views.setOnClickResponse(
- R.id.layout,
- RemoteViews.RemoteResponse.fromPendingIntent(pendingIntent));
-
- Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
- views.visitUris(visitor);
- verify(visitor, times(1)).accept(eq(fillIntentUri));
- verify(visitor, times(1)).accept(eq(pendingIntentUri));
- }
-
- private PendingIntent getPendingIntentWithUri(Uri uri) {
- return PendingIntent.getActivity(mContext, 0,
- new Intent("action", uri),
- PendingIntent.FLAG_IMMUTABLE);
- }
-
- @Test
public void layoutInflaterFactory_nothingSet_returnsNull() {
final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test);
assertNull(rv.getLayoutInflaterFactory());
diff --git a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
index f34b185b1c5a..c9536b9b8129 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
@@ -57,6 +57,16 @@ public class LongArrayMultiStateCounterTest {
}
@Test
+ public void setValue() {
+ LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4);
+
+ counter.setValues(0, new long[]{1, 2, 3, 4});
+ counter.setValues(1, new long[]{5, 6, 7, 8});
+ assertCounts(counter, 0, new long[]{1, 2, 3, 4});
+ assertCounts(counter, 1, new long[]{5, 6, 7, 8});
+ }
+
+ @Test
public void setEnabled() {
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4);
counter.setState(0, 1000);
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/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/OWNERS b/libs/WindowManager/Shell/OWNERS
index f0ed6ee5cb67..e346b51a4f19 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,4 @@
xutan@google.com
# Give submodule owners in shell resource approval
-per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com
+per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, nmusgrave@google.com, pbdr@google.com, tkachenkoi@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index b1b196d40357..fe65fdd30e48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -16,6 +16,7 @@
package com.android.wm.shell;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -168,6 +169,13 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
private final Object mLock = new Object();
private StartingWindowController mStartingWindow;
+ /** Overlay surface for home root task */
+ private final SurfaceControl mHomeTaskOverlayContainer = new SurfaceControl.Builder()
+ .setName("home_task_overlay_container")
+ .setContainerLayer()
+ .setHidden(false)
+ .build();
+
/**
* In charge of showing compat UI. Can be {@code null} if the device doesn't support size
* compat or if this isn't the main {@link ShellTaskOrganizer}.
@@ -428,6 +436,14 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
}
+ /**
+ * Returns a surface which can be used to attach overlays to the home root task
+ */
+ @NonNull
+ public SurfaceControl getHomeTaskOverlayContainer() {
+ return mHomeTaskOverlayContainer;
+ }
+
@Override
public void addStartingWindow(StartingWindowInfo info) {
if (mStartingWindow != null) {
@@ -485,6 +501,15 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
if (mUnfoldAnimationController != null) {
mUnfoldAnimationController.onTaskAppeared(info.getTaskInfo(), info.getLeash());
}
+
+ if (info.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) {
+ ProtoLog.v(WM_SHELL_TASK_ORG, "Adding overlay to home task");
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setLayer(mHomeTaskOverlayContainer, Integer.MAX_VALUE);
+ t.reparent(mHomeTaskOverlayContainer, info.getLeash());
+ t.apply();
+ }
+
notifyLocusVisibilityIfNeeded(info.getTaskInfo());
notifyCompatUI(info.getTaskInfo(), listener);
mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskAdded(info.getTaskInfo()));
@@ -579,6 +604,12 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
notifyCompatUI(taskInfo, null /* taskListener */);
// Notify the recent tasks that a task has been removed
mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskRemoved(taskInfo));
+ if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.reparent(mHomeTaskOverlayContainer, null);
+ t.apply();
+ ProtoLog.v(WM_SHELL_TASK_ORG, "Removing overlay surface");
+ }
if (!ENABLE_SHELL_TRANSITIONS && (appearedInfo.getLeash() != null)) {
// Preemptively clean up the leash only if shell transitions are not enabled
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/compatui/UserAspectRatioSettingsWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
index ef763ec45994..afd3b14e8b1d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Rect;
import android.os.SystemClock;
import android.view.LayoutInflater;
@@ -227,9 +228,12 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract
}
private boolean getHasUserAspectRatioSettingsButton(@NonNull TaskInfo taskInfo) {
+ final Intent intent = taskInfo.baseIntent;
return taskInfo.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton
&& (taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed
|| taskInfo.appCompatTaskInfo.isUserFullscreenOverrideEnabled)
+ && Intent.ACTION_MAIN.equals(intent.getAction())
+ && intent.hasCategory(Intent.CATEGORY_LAUNCHER)
&& (!mUserAspectRatioButtonShownChecker.get() || isShowingButton());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
index deb7c6db338f..1385f42bc676 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
@@ -1,3 +1,7 @@
# WM shell sub-module desktop owners
atsjenk@google.com
+jorgegil@google.com
madym@google.com
+nmusgrave@google.com
+pbdr@google.com
+tkachenkoi@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
index a3803ed82844..8a0eea0a9bdd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
@@ -2,3 +2,6 @@
atsjenk@google.com
jorgegil@google.com
madym@google.com
+nmusgrave@google.com
+pbdr@google.com
+tkachenkoi@google.com
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..77427d999aaf 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
@@ -1666,7 +1666,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,
@@ -1860,9 +1860,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);
}
}
@@ -2325,7 +2326,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 +2599,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 +2702,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;
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/transition/IShellTransitions.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
index 644a6a5114a7..7f4a8f1d476a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
@@ -16,6 +16,7 @@
package com.android.wm.shell.transition;
+import android.view.SurfaceControl;
import android.window.RemoteTransition;
import android.window.TransitionFilter;
@@ -42,6 +43,13 @@ interface IShellTransitions {
*/
IBinder getShellApplyToken() = 3;
- /** Set listener that will receive callbacks about transitions involving home activity */
+ /**
+ * Set listener that will receive callbacks about transitions involving home activity.
+ */
oneway void setHomeTransitionListener(in IHomeTransitionListener listener) = 4;
+
+ /**
+ * Returns a container surface for the home root task.
+ */
+ SurfaceControl getHomeTaskOverlayContainer() = 5;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index b98762d5e104..af69b5272ad5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -64,7 +64,6 @@ import android.window.TransitionInfo;
import android.window.TransitionMetrics;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
import androidx.annotation.BinderThread;
@@ -72,6 +71,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
@@ -172,7 +172,7 @@ public class Transitions implements RemoteCallable<Transitions>,
/** Transition to animate task to desktop. */
public static final int TRANSIT_MOVE_TO_DESKTOP = WindowManager.TRANSIT_FIRST_CUSTOM + 15;
- private final WindowOrganizer mOrganizer;
+ private final ShellTaskOrganizer mOrganizer;
private final Context mContext;
private final ShellExecutor mMainExecutor;
private final ShellExecutor mAnimExecutor;
@@ -264,7 +264,7 @@ public class Transitions implements RemoteCallable<Transitions>,
public Transitions(@NonNull Context context,
@NonNull ShellInit shellInit,
@NonNull ShellController shellController,
- @NonNull WindowOrganizer organizer,
+ @NonNull ShellTaskOrganizer organizer,
@NonNull TransactionPool pool,
@NonNull DisplayController displayController,
@NonNull ShellExecutor mainExecutor,
@@ -280,7 +280,7 @@ public class Transitions implements RemoteCallable<Transitions>,
@NonNull ShellInit shellInit,
@Nullable ShellCommandHandler shellCommandHandler,
@NonNull ShellController shellController,
- @NonNull WindowOrganizer organizer,
+ @NonNull ShellTaskOrganizer organizer,
@NonNull TransactionPool pool,
@NonNull DisplayController displayController,
@NonNull ShellExecutor mainExecutor,
@@ -1240,6 +1240,10 @@ public class Transitions implements RemoteCallable<Transitions>,
}
}
+ private SurfaceControl getHomeTaskOverlayContainer() {
+ return mOrganizer.getHomeTaskOverlayContainer();
+ }
+
/**
* Interface for a callback that must be called after a TransitionHandler finishes playing an
* animation.
@@ -1470,6 +1474,17 @@ public class Transitions implements RemoteCallable<Transitions>,
listener);
});
}
+
+ @Override
+ public SurfaceControl getHomeTaskOverlayContainer() {
+ SurfaceControl[] result = new SurfaceControl[1];
+ executeRemoteCallWithTaskPermission(mTransitions, "getHomeTaskOverlayContainer",
+ (controller) -> {
+ result[0] = controller.getHomeTaskOverlayContainer();
+ }, true /* blocking */);
+ // Return a copy as writing to parcel releases the original surface
+ return new SurfaceControl(result[0], "Transitions.HomeOverlay");
+ }
}
private class SettingsObserver extends ContentObserver {
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index deebad545c5e..d718e157afdb 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -9,3 +9,6 @@ hwwang@google.com
chenghsiuchang@google.com
atsjenk@google.com
jorgegil@google.com
+nmusgrave@google.com
+pbdr@google.com
+tkachenkoi@google.com
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/compatui/UserAspectRatioSettingsWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
index 065293960da7..9fe2cb11e804 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
@@ -16,6 +16,9 @@
package com.android.wm.shell.compatui;
+import static android.content.Intent.ACTION_MAIN;
+import static android.content.Intent.CATEGORY_LAUNCHER;
+import static android.hardware.usb.UsbManager.ACTION_USB_STATE;
import static android.view.WindowInsets.Type.navigationBars;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -33,6 +36,7 @@ import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
import android.app.TaskInfo;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
@@ -108,7 +112,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
MockitoAnnotations.initMocks(this);
mExecutor = new TestShellExecutor();
mTaskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- false, /* topActivityBoundsLetterboxed */ true);
+ false, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
mWindowManager = new UserAspectRatioSettingsWindowManager(mContext, mTaskInfo,
mSyncTransactionQueue, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
mOnUserAspectRatioSettingsButtonClicked, mExecutor, flags -> 0,
@@ -179,7 +183,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
// No diff
clearInvocations(mWindowManager);
TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- true, /* topActivityBoundsLetterboxed */ true);
+ true, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
assertTrue(mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true));
verify(mWindowManager, never()).updateSurfacePosition();
@@ -200,7 +204,24 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
clearInvocations(mWindowManager);
clearInvocations(mLayout);
taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- false, /* topActivityBoundsLetterboxed */ true);
+ false, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
+ assertFalse(
+ mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true));
+ verify(mWindowManager).release();
+
+ // Recreate button
+ clearInvocations(mWindowManager);
+ taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+ true, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
+ assertTrue(mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true));
+
+ verify(mWindowManager).release();
+ verify(mWindowManager).createLayout(/* canShow= */ true);
+
+ // Change has no launcher category and is not main intent, dispose the component
+ clearInvocations(mWindowManager);
+ taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+ true, /* topActivityBoundsLetterboxed */ true, ACTION_USB_STATE, "");
assertFalse(
mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true));
verify(mWindowManager).release();
@@ -217,7 +238,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
// inflated
clearInvocations(mWindowManager);
TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- false, /* topActivityBoundsLetterboxed */ true);
+ false, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
verify(mWindowManager, never()).inflateLayout();
@@ -225,7 +246,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
// Change topActivityInSizeCompat to true and pass canShow true, layout should be inflated.
clearInvocations(mWindowManager);
taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- true, /* topActivityBoundsLetterboxed */ true);
+ true, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
verify(mWindowManager).inflateLayout();
@@ -304,7 +325,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
clearInvocations(mWindowManager);
spyOn(mWindowManager);
TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- true, /* topActivityBoundsLetterboxed */ true);
+ true, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
// User aspect ratio settings button has not yet been shown.
doReturn(false).when(mUserAspectRatioButtonShownChecker).get();
@@ -378,7 +399,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
}
private static TaskInfo createTaskInfo(boolean eligibleForUserAspectRatioButton,
- boolean topActivityBoundsLetterboxed) {
+ boolean topActivityBoundsLetterboxed, String action, String category) {
ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.taskId = TASK_ID;
taskInfo.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton =
@@ -386,6 +407,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed = topActivityBoundsLetterboxed;
taskInfo.configuration.uiMode &= ~Configuration.UI_MODE_TYPE_DESK;
taskInfo.realActivity = new ComponentName("com.mypackage.test", "TestActivity");
+ taskInfo.baseIntent = new Intent(action).addCategory(category);
return taskInfo;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
index 50802c3759c9..66efa02de764 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
@@ -40,12 +40,12 @@ import android.os.RemoteException;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionInfo.TransitionMode;
-import android.window.WindowOrganizer;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
@@ -68,7 +68,7 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class HomeTransitionObserverTest extends ShellTestCase {
- private final WindowOrganizer mOrganizer = mock(WindowOrganizer.class);
+ private final ShellTaskOrganizer mOrganizer = mock(ShellTaskOrganizer.class);
private final TransactionPool mTransactionPool = mock(TransactionPool.class);
private final Context mContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 01c9bd0cb9f7..e22bf3de30e4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -87,7 +87,6 @@ import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -98,6 +97,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
@@ -130,7 +130,7 @@ import java.util.function.Function;
@RunWith(AndroidJUnit4.class)
public class ShellTransitionTests extends ShellTestCase {
- private final WindowOrganizer mOrganizer = mock(WindowOrganizer.class);
+ private final ShellTaskOrganizer mOrganizer = mock(ShellTaskOrganizer.class);
private final TransactionPool mTransactionPool = mock(TransactionPool.class);
private final Context mContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 79a735786c38..47411701e5ab 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -79,14 +79,6 @@ cc_defaults {
"external/skia/src/core",
],
- product_variables: {
- eng: {
- lto: {
- never: true,
- },
- },
- },
-
target: {
android: {
include_dirs: [
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/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 281eba66123b..6019aa8560e1 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -156,7 +156,7 @@
<string name="permission_storage">Photos and media</string>
<!-- Notification permission will be granted of corresponding profile [CHAR LIMIT=30] -->
- <string name="permission_notification">Notifications</string>
+ <string name="permission_notifications">Notifications</string>
<!-- Apps permission will be granted of corresponding profile [CHAR LIMIT=30] -->
<string name="permission_app_streaming">Apps</string>
@@ -165,28 +165,31 @@
<string name="permission_nearby_device_streaming">Streaming</string>
<!-- Description of phone permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_phone_summary">Can make and manage phone calls</string>
+ <string name="permission_phone_summary">Make and manage phone calls</string>
<!-- Description of Call logs permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_call_logs_summary">Can read and write phone call log</string>
+ <string name="permission_call_logs_summary">Read and write phone call log</string>
<!-- Description of SMS permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_sms_summary">Can send and view SMS messages</string>
+ <string name="permission_sms_summary">Send and view SMS messages</string>
<!-- Description of contacts permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_contacts_summary">Can access your contacts</string>
+ <string name="permission_contacts_summary">Access your contacts</string>
<!-- Description of calendar permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_calendar_summary">Can access your calendar</string>
+ <string name="permission_calendar_summary">Access your calendar</string>
<!-- Description of microphone permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_microphone_summary">Can record audio</string>
+ <string name="permission_microphone_summary">Record audio</string>
<!-- Description of nearby devices' permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_nearby_devices_summary">Can find, connect to, and determine the relative position of nearby devices</string>
+ <string name="permission_nearby_devices_summary">Find, connect to, and determine the relative position of nearby devices</string>
- <!-- Description of notification permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_notification_summary">Can read all notifications, including information like contacts, messages, and photos</string>
+ <!-- Description of NLA (notification listener access) of corresponding profile [CHAR LIMIT=NONE] -->
+ <string name="permission_notification_listener_access_summary">Read all notifications, including information like contacts, messages, and photos</string>
+
+ <!-- Description of NLA & POST_NOTIFICATION of corresponding profile [CHAR LIMIT=NONE] -->
+ <string name="permission_notifications_summary">\u2022 Read all notifications, including info like contacts, messages, and photos&lt;br/>\u2022 Send notifications&lt;br/>&lt;br/>You can manage this app\'s ability to read and send notifications anytime in Settings > Notifications.</string>
<!-- Description of app streaming permission of corresponding profile [CHAR LIMIT=NONE] -->
<string name="permission_app_streaming_summary">Stream your phone\u2019s apps</string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 1184112fe3da..66282dc209ed 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -27,13 +27,13 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState;
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
-import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_TYPES;
-import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILES_NAME;
-import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_ICON;
-import static com.android.companiondevicemanager.CompanionDeviceResources.SUMMARIES;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_PERMISSIONS;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_NAMES;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_ICONS;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_SUMMARIES;
import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_PROFILES;
import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_SELF_MANAGED_PROFILES;
-import static com.android.companiondevicemanager.CompanionDeviceResources.TITLES;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_TITLES;
import static com.android.companiondevicemanager.Utils.getApplicationLabel;
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
import static com.android.companiondevicemanager.Utils.getIcon;
@@ -482,7 +482,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
return;
}
- title = getHtmlFromResources(this, TITLES.get(deviceProfile), deviceName);
+ title = getHtmlFromResources(this, PROFILE_TITLES.get(deviceProfile), deviceName);
setupPermissionList(deviceProfile);
// Summary is not needed for selfManaged dialog.
@@ -525,7 +525,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
- final Drawable profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile));
+ 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.
@@ -554,14 +554,14 @@ public class CompanionDeviceActivity extends FragmentActivity implements
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
- profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile));
+ profileIcon = getIcon(this, PROFILE_ICONS.get(deviceProfile));
if (deviceProfile == null) {
title = getHtmlFromResources(this, R.string.chooser_title_non_profile, appLabel);
mButtonNotAllowMultipleDevices.setText(R.string.consent_no);
} else {
title = getHtmlFromResources(this,
- R.string.chooser_title, getString(PROFILES_NAME.get(deviceProfile)));
+ R.string.chooser_title, getString(PROFILE_NAMES.get(deviceProfile)));
}
mDeviceAdapter = new DeviceListAdapter(this, this::onDeviceClicked);
@@ -626,10 +626,10 @@ public class CompanionDeviceActivity extends FragmentActivity implements
private void updatePermissionUi() {
final String deviceProfile = mRequest.getDeviceProfile();
- final int summaryResourceId = SUMMARIES.get(deviceProfile);
+ final int summaryResourceId = PROFILE_SUMMARIES.get(deviceProfile);
final String remoteDeviceName = mSelectedDevice.getDisplayName();
final Spanned title = getHtmlFromResources(
- this, TITLES.get(deviceProfile), mAppLabel, remoteDeviceName);
+ this, PROFILE_TITLES.get(deviceProfile), mAppLabel, remoteDeviceName);
final Spanned summary;
if (deviceProfile == null && mRequest.isSingleDevice()) {
@@ -689,7 +689,8 @@ public class CompanionDeviceActivity extends FragmentActivity implements
// and when mPermissionListRecyclerView is fully populated.
// Lastly, disable the Allow and Don't allow buttons.
private void setupPermissionList(String deviceProfile) {
- final List<Integer> permissionTypes = new ArrayList<>(PERMISSION_TYPES.get(deviceProfile));
+ final List<Integer> permissionTypes = new ArrayList<>(
+ PROFILE_PERMISSIONS.get(deviceProfile));
mPermissionListAdapter.setPermissionType(permissionTypes);
mPermissionListRecyclerView.setAdapter(mPermissionListAdapter);
mPermissionListRecyclerView.setLayoutManager(mPermissionsLayoutManager);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
index 551e9754032b..23a11d618085 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
@@ -22,28 +22,15 @@ import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
import static android.companion.AssociationRequest.DEVICE_PROFILE_GLASSES;
import static android.companion.AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
-
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_APP_STREAMING;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CALENDAR;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CALL_LOGS;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CHANGE_MEDIA_OUTPUT;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CONTACTS;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_MICROPHONE;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_NEARBY_DEVICES;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_NEARBY_DEVICE_STREAMING;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_NOTIFICATION;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_PHONE;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_SMS;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_STORAGE;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static java.util.Collections.unmodifiableMap;
import static java.util.Collections.unmodifiableSet;
+import android.os.Build;
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.media.flags.Flags;
-
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -54,7 +41,85 @@ import java.util.Set;
* for the corresponding profile.
*/
final class CompanionDeviceResources {
- static final Map<String, Integer> TITLES;
+
+ // Permission resources
+ private static final int PERMISSION_NOTIFICATION_LISTENER_ACCESS = 0;
+ private static final int PERMISSION_STORAGE = 1;
+ private static final int PERMISSION_APP_STREAMING = 2;
+ private static final int PERMISSION_PHONE = 3;
+ private static final int PERMISSION_SMS = 4;
+ private static final int PERMISSION_CONTACTS = 5;
+ private static final int PERMISSION_CALENDAR = 6;
+ private static final int PERMISSION_NEARBY_DEVICES = 7;
+ private static final int PERMISSION_NEARBY_DEVICE_STREAMING = 8;
+ private static final int PERMISSION_MICROPHONE = 9;
+ private static final int PERMISSION_CALL_LOGS = 10;
+ // Notification Listener Access & POST_NOTIFICATION permission
+ private static final int PERMISSION_NOTIFICATIONS = 11;
+ private static final int PERMISSION_CHANGE_MEDIA_OUTPUT = 12;
+
+ static final Map<Integer, Integer> PERMISSION_TITLES;
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(PERMISSION_NOTIFICATION_LISTENER_ACCESS, R.string.permission_notifications);
+ map.put(PERMISSION_STORAGE, R.string.permission_storage);
+ map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming);
+ map.put(PERMISSION_PHONE, R.string.permission_phone);
+ map.put(PERMISSION_SMS, R.string.permission_sms);
+ map.put(PERMISSION_CONTACTS, R.string.permission_contacts);
+ map.put(PERMISSION_CALENDAR, R.string.permission_calendar);
+ map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices);
+ map.put(PERMISSION_NEARBY_DEVICE_STREAMING, R.string.permission_nearby_device_streaming);
+ map.put(PERMISSION_MICROPHONE, R.string.permission_microphone);
+ map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs);
+ map.put(PERMISSION_NOTIFICATIONS, R.string.permission_notifications);
+ map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.string.permission_media_routing_control);
+ PERMISSION_TITLES = unmodifiableMap(map);
+ }
+
+ static final Map<Integer, Integer> PERMISSION_SUMMARIES;
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(PERMISSION_NOTIFICATION_LISTENER_ACCESS,
+ R.string.permission_notification_listener_access_summary);
+ map.put(PERMISSION_STORAGE, R.string.permission_storage_summary);
+ map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming_summary);
+ map.put(PERMISSION_PHONE, R.string.permission_phone_summary);
+ map.put(PERMISSION_SMS, R.string.permission_sms_summary);
+ map.put(PERMISSION_CONTACTS, R.string.permission_contacts_summary);
+ map.put(PERMISSION_CALENDAR, R.string.permission_calendar_summary);
+ map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices_summary);
+ map.put(PERMISSION_NEARBY_DEVICE_STREAMING,
+ R.string.permission_nearby_device_streaming_summary);
+ map.put(PERMISSION_MICROPHONE, R.string.permission_microphone_summary);
+ map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs_summary);
+ map.put(PERMISSION_NOTIFICATIONS, R.string.permission_notifications_summary);
+ map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.string.permission_media_routing_control_summary);
+ PERMISSION_SUMMARIES = unmodifiableMap(map);
+ }
+
+ static final Map<Integer, Integer> PERMISSION_ICONS;
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(PERMISSION_NOTIFICATION_LISTENER_ACCESS, R.drawable.ic_permission_notifications);
+ map.put(PERMISSION_STORAGE, R.drawable.ic_permission_storage);
+ map.put(PERMISSION_APP_STREAMING, R.drawable.ic_permission_app_streaming);
+ map.put(PERMISSION_PHONE, R.drawable.ic_permission_phone);
+ map.put(PERMISSION_SMS, R.drawable.ic_permission_sms);
+ map.put(PERMISSION_CONTACTS, R.drawable.ic_permission_contacts);
+ map.put(PERMISSION_CALENDAR, R.drawable.ic_permission_calendar);
+ map.put(PERMISSION_NEARBY_DEVICES, R.drawable.ic_permission_nearby_devices);
+ map.put(PERMISSION_NEARBY_DEVICE_STREAMING,
+ R.drawable.ic_permission_nearby_device_streaming);
+ map.put(PERMISSION_MICROPHONE, R.drawable.ic_permission_microphone);
+ map.put(PERMISSION_CALL_LOGS, R.drawable.ic_permission_call_logs);
+ map.put(PERMISSION_NOTIFICATIONS, R.drawable.ic_permission_notifications);
+ map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.drawable.ic_permission_media_routing_control);
+ PERMISSION_ICONS = unmodifiableMap(map);
+ }
+
+ // Profile resources
+ static final Map<String, Integer> PROFILE_TITLES;
static {
final Map<String, Integer> map = new ArrayMap<>();
map.put(DEVICE_PROFILE_APP_STREAMING, R.string.title_app_streaming);
@@ -65,71 +130,61 @@ final class CompanionDeviceResources {
map.put(DEVICE_PROFILE_GLASSES, R.string.confirmation_title_glasses);
map.put(null, R.string.confirmation_title);
- TITLES = unmodifiableMap(map);
+ PROFILE_TITLES = unmodifiableMap(map);
+ }
+
+ static final Map<String, Integer> PROFILE_SUMMARIES;
+ static {
+ final Map<String, Integer> map = new ArrayMap<>();
+ map.put(DEVICE_PROFILE_WATCH, R.string.summary_watch);
+ map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses);
+ map.put(null, R.string.summary_generic);
+
+ PROFILE_SUMMARIES = unmodifiableMap(map);
}
- static final Map<String, List<Integer>> PERMISSION_TYPES;
+ static final Map<String, List<Integer>> PROFILE_PERMISSIONS;
static {
final Map<String, List<Integer>> map = new ArrayMap<>();
map.put(DEVICE_PROFILE_APP_STREAMING, Arrays.asList(PERMISSION_APP_STREAMING));
map.put(DEVICE_PROFILE_COMPUTER, Arrays.asList(
- PERMISSION_NOTIFICATION, PERMISSION_STORAGE));
+ PERMISSION_NOTIFICATION_LISTENER_ACCESS, PERMISSION_STORAGE));
map.put(DEVICE_PROFILE_NEARBY_DEVICE_STREAMING,
Arrays.asList(PERMISSION_NEARBY_DEVICE_STREAMING));
- if (!Flags.enablePrivilegedRoutingForMediaRoutingControl()) {
- map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_PHONE,
- PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_CALENDAR,
- PERMISSION_NEARBY_DEVICES));
- } else {
- map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_PHONE,
+ if (Build.VERSION.SDK_INT > UPSIDE_DOWN_CAKE) {
+ map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATIONS, PERMISSION_PHONE,
PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_CALENDAR,
PERMISSION_NEARBY_DEVICES, PERMISSION_CHANGE_MEDIA_OUTPUT));
+ } else {
+ map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATION_LISTENER_ACCESS,
+ PERMISSION_PHONE, PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS,
+ PERMISSION_CALENDAR, PERMISSION_NEARBY_DEVICES));
}
- map.put(DEVICE_PROFILE_GLASSES, Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_PHONE,
- PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_MICROPHONE,
+ map.put(DEVICE_PROFILE_GLASSES, Arrays.asList(PERMISSION_NOTIFICATION_LISTENER_ACCESS,
+ PERMISSION_PHONE, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_MICROPHONE,
PERMISSION_NEARBY_DEVICES));
- PERMISSION_TYPES = unmodifiableMap(map);
+ PROFILE_PERMISSIONS = unmodifiableMap(map);
}
- static final Map<String, Integer> SUMMARIES;
- static {
- final Map<String, Integer> map = new ArrayMap<>();
- map.put(DEVICE_PROFILE_WATCH, R.string.summary_watch);
- map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses);
- map.put(null, R.string.summary_generic);
-
- SUMMARIES = unmodifiableMap(map);
- }
-
- static final Map<String, Integer> PROFILES_NAME;
+ static final Map<String, Integer> PROFILE_NAMES;
static {
final Map<String, Integer> map = new ArrayMap<>();
map.put(DEVICE_PROFILE_WATCH, R.string.profile_name_watch);
map.put(DEVICE_PROFILE_GLASSES, R.string.profile_name_glasses);
map.put(null, R.string.profile_name_generic);
- PROFILES_NAME = unmodifiableMap(map);
- }
-
- static final Map<String, Integer> PROFILES_NAME_MULTI;
- static {
- final Map<String, Integer> map = new ArrayMap<>();
- map.put(DEVICE_PROFILE_GLASSES, R.string.profile_name_generic);
- map.put(DEVICE_PROFILE_WATCH, R.string.profile_name_watch);
- map.put(null, R.string.profile_name_generic);
-
- PROFILES_NAME_MULTI = unmodifiableMap(map);
+ PROFILE_NAMES = unmodifiableMap(map);
}
- static final Map<String, Integer> PROFILE_ICON;
+ static final Map<String, Integer> PROFILE_ICONS;
static {
final Map<String, Integer> map = new ArrayMap<>();
map.put(DEVICE_PROFILE_WATCH, R.drawable.ic_watch);
map.put(DEVICE_PROFILE_GLASSES, R.drawable.ic_glasses);
map.put(null, R.drawable.ic_device_other);
- PROFILE_ICON = unmodifiableMap(map);
+ PROFILE_ICONS = unmodifiableMap(map);
}
static final Set<String> SUPPORTED_PROFILES;
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
index e21aee3cedb8..4a1f8014a2f0 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
@@ -16,14 +16,14 @@
package com.android.companiondevicemanager;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_ICONS;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_SUMMARIES;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_TITLES;
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
import static com.android.companiondevicemanager.Utils.getIcon;
-import static java.util.Collections.unmodifiableMap;
-
import android.content.Context;
import android.text.Spanned;
-import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -35,7 +35,6 @@ import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
-import java.util.Map;
class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.ViewHolder> {
private final Context mContext;
@@ -43,75 +42,6 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
// Add the expand buttons if permissions are more than PERMISSION_SIZE in the permission list.
private static final int PERMISSION_SIZE = 2;
- static final int PERMISSION_NOTIFICATION = 0;
- static final int PERMISSION_STORAGE = 1;
- static final int PERMISSION_APP_STREAMING = 2;
- static final int PERMISSION_PHONE = 3;
- static final int PERMISSION_SMS = 4;
- static final int PERMISSION_CONTACTS = 5;
- static final int PERMISSION_CALENDAR = 6;
- static final int PERMISSION_NEARBY_DEVICES = 7;
- static final int PERMISSION_NEARBY_DEVICE_STREAMING = 8;
- static final int PERMISSION_MICROPHONE = 9;
- static final int PERMISSION_CALL_LOGS = 10;
- static final int PERMISSION_CHANGE_MEDIA_OUTPUT = 11;
-
- private static final Map<Integer, Integer> sTitleMap;
- static {
- final Map<Integer, Integer> map = new ArrayMap<>();
- map.put(PERMISSION_NOTIFICATION, R.string.permission_notification);
- map.put(PERMISSION_STORAGE, R.string.permission_storage);
- map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming);
- map.put(PERMISSION_PHONE, R.string.permission_phone);
- map.put(PERMISSION_SMS, R.string.permission_sms);
- map.put(PERMISSION_CONTACTS, R.string.permission_contacts);
- map.put(PERMISSION_CALENDAR, R.string.permission_calendar);
- map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices);
- map.put(PERMISSION_NEARBY_DEVICE_STREAMING, R.string.permission_nearby_device_streaming);
- map.put(PERMISSION_MICROPHONE, R.string.permission_microphone);
- map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs);
- map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.string.permission_media_routing_control);
- sTitleMap = unmodifiableMap(map);
- }
-
- private static final Map<Integer, Integer> sSummaryMap;
- static {
- final Map<Integer, Integer> map = new ArrayMap<>();
- map.put(PERMISSION_NOTIFICATION, R.string.permission_notification_summary);
- map.put(PERMISSION_STORAGE, R.string.permission_storage_summary);
- map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming_summary);
- map.put(PERMISSION_PHONE, R.string.permission_phone_summary);
- map.put(PERMISSION_SMS, R.string.permission_sms_summary);
- map.put(PERMISSION_CONTACTS, R.string.permission_contacts_summary);
- map.put(PERMISSION_CALENDAR, R.string.permission_calendar_summary);
- map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices_summary);
- map.put(PERMISSION_NEARBY_DEVICE_STREAMING,
- R.string.permission_nearby_device_streaming_summary);
- map.put(PERMISSION_MICROPHONE, R.string.permission_microphone_summary);
- map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs_summary);
- map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.string.permission_media_routing_control_summary);
- sSummaryMap = unmodifiableMap(map);
- }
-
- private static final Map<Integer, Integer> sIconMap;
- static {
- final Map<Integer, Integer> map = new ArrayMap<>();
- map.put(PERMISSION_NOTIFICATION, R.drawable.ic_permission_notifications);
- map.put(PERMISSION_STORAGE, R.drawable.ic_permission_storage);
- map.put(PERMISSION_APP_STREAMING, R.drawable.ic_permission_app_streaming);
- map.put(PERMISSION_PHONE, R.drawable.ic_permission_phone);
- map.put(PERMISSION_SMS, R.drawable.ic_permission_sms);
- map.put(PERMISSION_CONTACTS, R.drawable.ic_permission_contacts);
- map.put(PERMISSION_CALENDAR, R.drawable.ic_permission_calendar);
- map.put(PERMISSION_NEARBY_DEVICES, R.drawable.ic_permission_nearby_devices);
- map.put(PERMISSION_NEARBY_DEVICE_STREAMING,
- R.drawable.ic_permission_nearby_device_streaming);
- map.put(PERMISSION_MICROPHONE, R.drawable.ic_permission_microphone);
- map.put(PERMISSION_CALL_LOGS, R.drawable.ic_permission_call_logs);
- map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.drawable.ic_permission_media_routing_control);
- sIconMap = unmodifiableMap(map);
- }
-
PermissionListAdapter(Context context) {
mContext = context;
}
@@ -121,7 +51,8 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.list_item_permission, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
- viewHolder.mPermissionIcon.setImageDrawable(getIcon(mContext, sIconMap.get(viewType)));
+ viewHolder.mPermissionIcon.setImageDrawable(
+ getIcon(mContext, PERMISSION_ICONS.get(viewType)));
if (viewHolder.mExpandButton.getTag() == null) {
viewHolder.mExpandButton.setTag(R.drawable.btn_expand_more);
@@ -165,8 +96,8 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
int type = getItemViewType(position);
- final Spanned title = getHtmlFromResources(mContext, sTitleMap.get(type));
- final Spanned summary = getHtmlFromResources(mContext, sSummaryMap.get(type));
+ final Spanned title = getHtmlFromResources(mContext, PERMISSION_TITLES.get(type));
+ final Spanned summary = getHtmlFromResources(mContext, PERMISSION_SUMMARIES.get(type));
holder.mPermissionSummary.setText(summary);
holder.mPermissionName.setText(title);
@@ -192,6 +123,7 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
private final TextView mPermissionSummary;
private final ImageView mPermissionIcon;
private final ImageButton mExpandButton;
+
ViewHolder(View itemView) {
super(itemView);
mPermissionName = itemView.findViewById(R.id.permission_name);
@@ -203,7 +135,7 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
private void setAccessibility(View view, int viewType, int action, int statusResourceId,
int actionResourceId) {
- final String permission = mContext.getString(sTitleMap.get(viewType));
+ final String permission = mContext.getString(PERMISSION_TITLES.get(viewType));
if (actionResourceId != 0) {
view.announceForAccessibility(
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/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index 96a11eeb3b78..5b39f4ee1541 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -112,26 +112,6 @@ public class RestrictedLockUtils {
}
/**
- * Shows restricted setting dialog.
- */
- @RequiresApi(Build.VERSION_CODES.TIRAMISU)
- public static void sendShowRestrictedSettingDialogIntent(Context context,
- String packageName, int uid) {
- final Intent intent = getShowRestrictedSettingsIntent(packageName, uid);
- context.startActivity(intent);
- }
-
- /**
- * Gets restricted settings dialog intent.
- */
- private static Intent getShowRestrictedSettingsIntent(String packageName, int uid) {
- final Intent intent = new Intent(Settings.ACTION_SHOW_RESTRICTED_SETTING_DIALOG);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- intent.putExtra(Intent.EXTRA_UID, uid);
- return intent;
- }
-
- /**
* Checks if current user is profile or not
*/
@RequiresApi(Build.VERSION_CODES.M)
@@ -238,4 +218,35 @@ public class RestrictedLockUtils {
+ '}';
}
}
+
+
+ /**
+ * Shows restricted setting dialog.
+ *
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public static void sendShowRestrictedSettingDialogIntent(Context context,
+ String packageName, int uid) {
+ final Intent intent = getShowRestrictedSettingsIntent(packageName, uid);
+ context.startActivity(intent);
+ }
+
+ /**
+ * Gets restricted settings dialog intent.
+ *
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
+ private static Intent getShowRestrictedSettingsIntent(String packageName, int uid) {
+ final Intent intent = new Intent(Settings.ACTION_SHOW_RESTRICTED_SETTING_DIALOG);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ return intent;
+ }
}
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 4454b710b7e4..02374462f093 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -77,6 +77,9 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
ECM_KEYS.add(AppOpsManager.OPSTR_LOADER_USAGE_STATS);
ECM_KEYS.add(Manifest.permission.BIND_DEVICE_ADMIN);
}
+
+ ECM_KEYS.add(AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS);
+ ECM_KEYS.add(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE);
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
index db2a6ec2da68..50e3bd08026c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
@@ -96,12 +96,29 @@ public class RestrictedPreference extends TwoTargetPreference {
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
+ /**
+ * Checks if the given setting is subject to Enhanced Confirmation Mode restrictions for this
+ * package. Marks the preference as disabled if so.
+ * @param restriction The key identifying the setting
+ * @param packageName the package to check the restriction for
+ * @param uid the uid of the package
+ */
+ public void checkEcmRestrictionAndSetDisabled(String restriction, String packageName, int uid) {
+ mHelper.checkEcmRestrictionAndSetDisabled(restriction, packageName, uid);
+ }
+
@Override
public void setEnabled(boolean enabled) {
if (enabled && isDisabledByAdmin()) {
mHelper.setDisabledByAdmin(null);
return;
}
+
+ if (enabled && isDisabledByEcm()) {
+ mHelper.setDisabledByEcm(null);
+ return;
+ }
+
super.setEnabled(enabled);
}
@@ -111,16 +128,14 @@ public class RestrictedPreference extends TwoTargetPreference {
}
}
- public void setDisabledByAppOps(boolean disabled) {
- if (mHelper.setDisabledByAppOps(disabled)) {
- notifyChanged();
- }
- }
-
public boolean isDisabledByAdmin() {
return mHelper.isDisabledByAdmin();
}
+ public boolean isDisabledByEcm() {
+ return mHelper.isDisabledByEcm();
+ }
+
public int getUid() {
return mHelper != null ? mHelper.uid : Process.INVALID_UID;
}
@@ -128,4 +143,16 @@ public class RestrictedPreference extends TwoTargetPreference {
public String getPackageName() {
return mHelper != null ? mHelper.packageName : null;
}
+
+ /**
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
+ public void setDisabledByAppOps(boolean disabled) {
+ if (mHelper.setDisabledByAppOps(disabled)) {
+ notifyChanged();
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 29ea25e13835..a479269f40fb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -17,10 +17,12 @@
package com.android.settingslib;
import static android.app.admin.DevicePolicyResources.Strings.Settings.CONTROLLED_BY_ADMIN_SUMMARY;
+
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.Intent;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.UserHandle;
@@ -52,7 +54,8 @@ public class RestrictedPreferenceHelper {
private String mAttrUserRestriction = null;
private boolean mDisabledSummary = false;
- private boolean mDisabledByAppOps;
+ private boolean mDisabledByEcm;
+ private Intent mDisabledByEcmIntent = null;
public RestrictedPreferenceHelper(Context context, Preference preference,
AttributeSet attrs, String packageName, int uid) {
@@ -101,7 +104,7 @@ public class RestrictedPreferenceHelper {
* Modify PreferenceViewHolder to add padlock if restriction is disabled.
*/
public void onBindViewHolder(PreferenceViewHolder holder) {
- if (mDisabledByAdmin || mDisabledByAppOps) {
+ if (mDisabledByAdmin || mDisabledByEcm) {
holder.itemView.setEnabled(true);
}
if (mDisabledSummary) {
@@ -112,7 +115,7 @@ public class RestrictedPreferenceHelper {
: mContext.getString(R.string.disabled_by_admin_summary_text);
if (mDisabledByAdmin) {
summaryView.setText(disabledText);
- } else if (mDisabledByAppOps) {
+ } else if (mDisabledByEcm) {
summaryView.setText(R.string.disabled_by_app_ops_text);
} else if (TextUtils.equals(disabledText, summaryView.getText())) {
// It's previously set to disabled text, clear it.
@@ -144,7 +147,12 @@ public class RestrictedPreferenceHelper {
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, mEnforcedAdmin);
return true;
}
- if (mDisabledByAppOps) {
+ if (mDisabledByEcm) {
+ if (android.security.Flags.extendEcmToAllSettings()) {
+ mContext.startActivity(mDisabledByEcmIntent);
+ return true;
+ }
+
RestrictedLockUtilsInternal.sendShowRestrictedSettingDialogIntent(mContext, packageName,
uid);
return true;
@@ -174,6 +182,20 @@ public class RestrictedPreferenceHelper {
}
/**
+ * Checks if the given setting is subject to Enhanced Confirmation Mode restrictions for this
+ * package. Marks the preference as disabled if so.
+ * @param restriction The key identifying the setting
+ * @param packageName the package to check the restriction for
+ * @param uid the uid of the package
+ */
+ public void checkEcmRestrictionAndSetDisabled(String restriction, String packageName, int uid) {
+ updatePackageDetails(packageName, uid);
+ Intent intent = RestrictedLockUtilsInternal.checkIfRequiresEnhancedConfirmation(
+ mContext, restriction, uid, packageName);
+ setDisabledByEcm(intent);
+ }
+
+ /**
* @return EnforcedAdmin if we have been passed the restriction in the xml.
*/
public EnforcedAdmin checkRestrictionEnforced() {
@@ -211,10 +233,19 @@ public class RestrictedPreferenceHelper {
return changed;
}
- public boolean setDisabledByAppOps(boolean disabled) {
+ /**
+ * Disable the preference based on the passed in Intent
+ * @param disabledIntent The intent which is started when the user clicks the disabled
+ * preference. If it is {@code null}, then this preference will be enabled. Otherwise, it will
+ * be disabled.
+ * @return true if the disabled state was changed.
+ */
+ public boolean setDisabledByEcm(Intent disabledIntent) {
+ boolean disabled = disabledIntent != null;
boolean changed = false;
- if (mDisabledByAppOps != disabled) {
- mDisabledByAppOps = disabled;
+ if (mDisabledByEcm != disabled) {
+ mDisabledByEcmIntent = disabledIntent;
+ mDisabledByEcm = disabled;
changed = true;
updateDisabledState();
}
@@ -226,8 +257,8 @@ public class RestrictedPreferenceHelper {
return mDisabledByAdmin;
}
- public boolean isDisabledByAppOps() {
- return mDisabledByAppOps;
+ public boolean isDisabledByEcm() {
+ return mDisabledByEcm;
}
public void updatePackageDetails(String packageName, int uid) {
@@ -236,13 +267,31 @@ public class RestrictedPreferenceHelper {
}
private void updateDisabledState() {
+ boolean isEnabled = !(mDisabledByAdmin || mDisabledByEcm);
if (!(mPreference instanceof RestrictedTopLevelPreference)) {
- mPreference.setEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
+ mPreference.setEnabled(isEnabled);
}
if (mPreference instanceof PrimarySwitchPreference) {
- ((PrimarySwitchPreference) mPreference)
- .setSwitchEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
+ ((PrimarySwitchPreference) mPreference).setSwitchEnabled(isEnabled);
}
}
+
+
+ /**
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
+ public boolean setDisabledByAppOps(boolean disabled) {
+ boolean changed = false;
+ if (mDisabledByEcm != disabled) {
+ mDisabledByEcm = disabled;
+ changed = true;
+ updateDisabledState();
+ }
+
+ return changed;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 60321eb1a9dc..3b8f66577f6e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -197,6 +197,17 @@ public class RestrictedSwitchPreference extends SwitchPreferenceCompat {
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
+ /**
+ * Checks if the given setting is subject to Enhanced Confirmation Mode restrictions for this
+ * package. Marks the preference as disabled if so.
+ * @param restriction The key identifying the setting
+ * @param packageName the package to check the restriction for
+ * @param uid the uid of the package
+ */
+ public void checkEcmRestrictionAndSetDisabled(String restriction, String packageName, int uid) {
+ mHelper.checkEcmRestrictionAndSetDisabled(restriction, packageName, uid);
+ }
+
@Override
public void setEnabled(boolean enabled) {
boolean changed = false;
@@ -204,8 +215,8 @@ public class RestrictedSwitchPreference extends SwitchPreferenceCompat {
mHelper.setDisabledByAdmin(null);
changed = true;
}
- if (enabled && isDisabledByAppOps()) {
- mHelper.setDisabledByAppOps(false);
+ if (enabled && isDisabledByEcm()) {
+ mHelper.setDisabledByEcm(null);
changed = true;
}
if (!changed) {
@@ -223,25 +234,50 @@ public class RestrictedSwitchPreference extends SwitchPreferenceCompat {
return mHelper.isDisabledByAdmin();
}
+ public boolean isDisabledByEcm() {
+ return mHelper.isDisabledByEcm();
+ }
+
+ /**
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
private void setDisabledByAppOps(boolean disabled) {
if (mHelper.setDisabledByAppOps(disabled)) {
notifyChanged();
}
}
- public boolean isDisabledByAppOps() {
- return mHelper.isDisabledByAppOps();
- }
-
+ /**
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
public int getUid() {
return mHelper != null ? mHelper.uid : Process.INVALID_UID;
}
+ /**
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
public String getPackageName() {
return mHelper != null ? mHelper.packageName : null;
}
- /** Updates enabled state based on associated package. */
+ /**
+ * Updates enabled state based on associated package
+ *
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
public void updateState(
@NonNull String packageName, int uid, boolean isEnableAllowed, boolean isEnabled) {
mHelper.updatePackageDetails(packageName, uid);
@@ -258,7 +294,7 @@ public class RestrictedSwitchPreference extends SwitchPreferenceCompat {
setEnabled(false);
} else if (isEnabled) {
setEnabled(true);
- } else if (appOpsAllowed && isDisabledByAppOps()) {
+ } else if (appOpsAllowed && isDisabledByEcm()) {
setEnabled(true);
} else if (!appOpsAllowed){
setDisabledByAppOps(true);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 69b61c74625e..2cb44ec39a23 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -31,7 +31,6 @@ import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothLeBroadcastSubgroup;
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,7 +41,6 @@ import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
import androidx.annotation.RequiresApi;
@@ -53,15 +51,17 @@ 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 +74,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 +96,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 +182,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 +193,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 +215,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 +267,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 +352,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,11 +368,11 @@ 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);
}
@@ -325,7 +381,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
public void setProgramInfo(String programInfo) {
- setProgramInfo(programInfo, /*updateContentResolver=*/ true);
+ setProgramInfo(programInfo, /* updateContentResolver= */ true);
}
private void setProgramInfo(String programInfo, boolean updateContentResolver) {
@@ -344,8 +400,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 +412,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 +430,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 +461,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 +489,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 +503,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 +542,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 +579,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 +588,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 +668,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 +698,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 +707,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 +716,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 +734,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 +775,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 +785,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 +799,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 +843,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/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d12d9d665a8c..bacab0f8f1e8 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -879,6 +879,9 @@
<uses-permission android:name="android.permission.GET_BINDING_UID_IMPORTANCE" />
+ <!-- Permissions required for CTS test - CtsAccessibilityServiceTestCases-->
+ <uses-permission android:name="android.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING" />
+
<application
android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 7061e2cb8a4e..f10ac1bf1e0a 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -204,6 +204,7 @@ android_library {
"lottie",
"LowLightDreamLib",
"motion_tool_lib",
+ "notification_flags_lib",
],
libs: [
"keepanno-annotations",
@@ -328,6 +329,7 @@ android_library {
"androidx.compose.ui_ui",
"flag-junit",
"platform-test-annotations",
+ "notification_flags_lib",
],
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index f7d9056c33dc..9c46ebdc5ac8 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -21,7 +21,6 @@ import android.app.ActivityTaskManager
import android.app.PendingIntent
import android.app.TaskInfo
import android.graphics.Matrix
-import android.graphics.Path
import android.graphics.Rect
import android.graphics.RectF
import android.os.Build
@@ -37,7 +36,6 @@ import android.view.SyncRtSurfaceTransactionApplier
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
-import android.view.animation.Interpolator
import android.view.animation.PathInterpolator
import androidx.annotation.AnyThread
import androidx.annotation.BinderThread
@@ -93,7 +91,7 @@ class ActivityLaunchAnimator(
val INTERPOLATORS =
LaunchAnimator.Interpolators(
positionInterpolator = Interpolators.EMPHASIZED,
- positionXInterpolator = createPositionXInterpolator(),
+ positionXInterpolator = Interpolators.EMPHASIZED_COMPLEMENT,
contentBeforeFadeOutInterpolator = Interpolators.LINEAR_OUT_SLOW_IN,
contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f)
)
@@ -121,16 +119,6 @@ class ActivityLaunchAnimator(
* cancelled by WM.
*/
private const val LONG_LAUNCH_TIMEOUT = 5_000L
-
- private fun createPositionXInterpolator(): Interpolator {
- val path =
- Path().apply {
- moveTo(0f, 0f)
- cubicTo(0.1217f, 0.0462f, 0.15f, 0.4686f, 0.1667f, 0.66f)
- cubicTo(0.1834f, 0.8878f, 0.1667f, 1f, 1f, 1f)
- }
- return PathInterpolator(path)
- }
}
/**
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..e538e093e60f 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
@@ -175,11 +175,7 @@ private fun <T> computeValue(
canOverflow: Boolean,
): T {
val state = layoutImpl.state.transitionState
- if (
- state !is TransitionState.Transition ||
- state.fromScene == state.toScene ||
- !layoutImpl.isTransitionReady(state)
- ) {
+ if (state !is TransitionState.Transition || !layoutImpl.isTransitionReady(state)) {
return sharedValue.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..de69c37d4630 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
@@ -47,12 +47,6 @@ internal fun CoroutineScope.animateToScene(
when (state) {
is TransitionState.Idle -> animate(layoutImpl, 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.
@@ -153,13 +147,13 @@ private fun CoroutineScope.animate(
}
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) {
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..431a8aef6d3d 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
@@ -288,7 +288,6 @@ private fun shouldDrawElement(
// 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
@@ -374,7 +373,7 @@ private fun isElementOpaque(
): Boolean {
val state = layoutImpl.state.transitionState
- if (state !is TransitionState.Transition || state.fromScene == state.toScene) {
+ if (state !is TransitionState.Transition) {
return true
}
@@ -611,7 +610,7 @@ private inline fun <T> computeValue(
val state = layoutImpl.state.transitionState
// There is no ongoing transition.
- if (state !is TransitionState.Transition || state.fromScene == state.toScene) {
+ if (state !is TransitionState.Transition) {
// Even if this element SceneTransitionLayout is not animated, the layout itself might be
// animated (e.g. by another parent SceneTransitionLayout), in which case this element still
// need to participate in the layout phase.
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..7029da2edb0d 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
@@ -131,10 +131,6 @@ private fun shouldComposeMovableElement(
val fromScene = (transitionState as TransitionState.Transition).fromScene
val toScene = transitionState.toScene
- if (fromScene == toScene) {
- check(fromScene == scene)
- return true
- }
val fromReady = layoutImpl.isSceneReady(fromScene)
val toReady = layoutImpl.isSceneReady(toScene)
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 ded6cc155b0b..32025b4f1258 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
@@ -73,37 +73,37 @@ enum class NestedScrollBehavior(val canStartOnPostFling: Boolean) {
internal fun Modifier.nestedScrollToScene(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
- startBehavior: NestedScrollBehavior,
- endBehavior: NestedScrollBehavior,
+ topOrLeftBehavior: NestedScrollBehavior,
+ bottomOrRightBehavior: NestedScrollBehavior,
) =
this then
NestedScrollToSceneElement(
layoutImpl = layoutImpl,
orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
private data class NestedScrollToSceneElement(
private val layoutImpl: SceneTransitionLayoutImpl,
private val orientation: Orientation,
- private val startBehavior: NestedScrollBehavior,
- private val endBehavior: NestedScrollBehavior,
+ private val topOrLeftBehavior: NestedScrollBehavior,
+ private val bottomOrRightBehavior: NestedScrollBehavior,
) : ModifierNodeElement<NestedScrollToSceneNode>() {
override fun create() =
NestedScrollToSceneNode(
layoutImpl = layoutImpl,
orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
override fun update(node: NestedScrollToSceneNode) {
node.update(
layoutImpl = layoutImpl,
orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
}
@@ -111,23 +111,23 @@ private data class NestedScrollToSceneElement(
name = "nestedScrollToScene"
properties["layoutImpl"] = layoutImpl
properties["orientation"] = orientation
- properties["startBehavior"] = startBehavior
- properties["endBehavior"] = endBehavior
+ properties["topOrLeftBehavior"] = topOrLeftBehavior
+ properties["bottomOrRightBehavior"] = bottomOrRightBehavior
}
}
private class NestedScrollToSceneNode(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
- startBehavior: NestedScrollBehavior,
- endBehavior: NestedScrollBehavior,
+ topOrLeftBehavior: NestedScrollBehavior,
+ bottomOrRightBehavior: NestedScrollBehavior,
) : DelegatingNode() {
private var priorityNestedScrollConnection: PriorityNestedScrollConnection =
scenePriorityNestedScrollConnection(
layoutImpl = layoutImpl,
orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
private var nestedScrollNode: DelegatableNode =
@@ -148,8 +148,8 @@ private class NestedScrollToSceneNode(
fun update(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
- startBehavior: NestedScrollBehavior,
- endBehavior: NestedScrollBehavior,
+ topOrLeftBehavior: NestedScrollBehavior,
+ bottomOrRightBehavior: NestedScrollBehavior,
) {
// Clean up the old nested scroll connection
priorityNestedScrollConnection.reset()
@@ -160,8 +160,8 @@ private class NestedScrollToSceneNode(
scenePriorityNestedScrollConnection(
layoutImpl = layoutImpl,
orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
nestedScrollNode =
nestedScrollModifierNode(
@@ -175,12 +175,12 @@ private class NestedScrollToSceneNode(
private fun scenePriorityNestedScrollConnection(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
- startBehavior: NestedScrollBehavior,
- endBehavior: NestedScrollBehavior,
+ topOrLeftBehavior: NestedScrollBehavior,
+ bottomOrRightBehavior: NestedScrollBehavior,
) =
SceneNestedScrollHandler(
gestureHandler = layoutImpl.gestureHandler(orientation = orientation),
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
.connection
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/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
index f5561cb404b6..6a7a3a00d4fe 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
@@ -86,16 +86,26 @@ private class SceneScopeImpl(
return element(layoutImpl, scene, key)
}
- override fun Modifier.nestedScrollToScene(
- orientation: Orientation,
- startBehavior: NestedScrollBehavior,
- endBehavior: NestedScrollBehavior,
+ override fun Modifier.horizontalNestedScrollToScene(
+ leftBehavior: NestedScrollBehavior,
+ rightBehavior: NestedScrollBehavior,
): Modifier =
nestedScrollToScene(
layoutImpl = layoutImpl,
- orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ orientation = Orientation.Horizontal,
+ topOrLeftBehavior = leftBehavior,
+ bottomOrRightBehavior = rightBehavior,
+ )
+
+ override fun Modifier.verticalNestedScrollToScene(
+ topBehavior: NestedScrollBehavior,
+ bottomBehavior: NestedScrollBehavior
+ ): Modifier =
+ nestedScrollToScene(
+ layoutImpl = layoutImpl,
+ orientation = Orientation.Vertical,
+ topOrLeftBehavior = topBehavior,
+ bottomOrRightBehavior = bottomBehavior,
)
@Composable
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 01179d3b8f73..91decf4d8b7e 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
@@ -49,8 +49,12 @@ internal class SceneGestureHandler(
layoutImpl.state.transitionState = value
}
- internal var swipeTransition: SwipeTransition = SwipeTransition(currentScene, currentScene, 1f)
- private set
+ private var _swipeTransition: SwipeTransition? = null
+ internal var swipeTransition: SwipeTransition
+ get() = _swipeTransition ?: error("SwipeTransition needs to be initialized")
+ set(value) {
+ _swipeTransition = value
+ }
private fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
if (isDrivingTransition || force) transitionState = newTransition
@@ -61,7 +65,7 @@ internal class SceneGestureHandler(
get() = layoutImpl.scene(transitionState.currentScene)
internal val isDrivingTransition
- get() = transitionState == swipeTransition
+ get() = transitionState == _swipeTransition
/**
* The velocity threshold at which the intent of the user is to swipe up or down. It is the same
@@ -82,12 +86,15 @@ 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
}
@@ -105,11 +112,8 @@ internal class SceneGestureHandler(
val fromScene = 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 +183,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 +206,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 +228,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 +359,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
+ transitionState = TransitionState.Idle(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)
@@ -410,15 +459,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
@@ -495,8 +540,8 @@ private class SceneDraggableHandler(
internal class SceneNestedScrollHandler(
private val gestureHandler: SceneGestureHandler,
- private val startBehavior: NestedScrollBehavior,
- private val endBehavior: NestedScrollBehavior,
+ private val topOrLeftBehavior: NestedScrollBehavior,
+ private val bottomOrRightBehavior: NestedScrollBehavior,
) : NestedScrollHandler {
override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
@@ -565,8 +610,8 @@ internal class SceneNestedScrollHandler(
canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
val behavior: NestedScrollBehavior =
when {
- offsetAvailable > 0f -> startBehavior
- offsetAvailable < 0f -> endBehavior
+ offsetAvailable > 0f -> topOrLeftBehavior
+ offsetAvailable < 0f -> bottomOrRightBehavior
else -> return@PriorityNestedScrollConnection false
}
@@ -594,8 +639,8 @@ internal class SceneNestedScrollHandler(
canStartPostFling = { velocityAvailable ->
val behavior: NestedScrollBehavior =
when {
- velocityAvailable > 0f -> startBehavior
- velocityAvailable < 0f -> endBehavior
+ velocityAvailable > 0f -> topOrLeftBehavior
+ velocityAvailable < 0f -> bottomOrRightBehavior
else -> return@PriorityNestedScrollConnection false
}
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 afa184b15901..239971ff6be8 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
@@ -126,14 +126,24 @@ interface SceneScope {
* Adds a [NestedScrollConnection] to intercept scroll events not handled by the scrollable
* component.
*
- * @param orientation is used to determine if we handle top/bottom or left/right events.
- * @param startBehavior when we should perform the overscroll animation at the top/left.
- * @param endBehavior when we should perform the overscroll animation at the bottom/right.
+ * @param leftBehavior when we should perform the overscroll animation at the left.
+ * @param rightBehavior when we should perform the overscroll animation at the right.
*/
- fun Modifier.nestedScrollToScene(
- orientation: Orientation,
- startBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
- endBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
+ fun Modifier.horizontalNestedScrollToScene(
+ leftBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
+ rightBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
+ ): Modifier
+
+ /**
+ * Adds a [NestedScrollConnection] to intercept scroll events not handled by the scrollable
+ * component.
+ *
+ * @param topBehavior when we should perform the overscroll animation at the top.
+ * @param bottomBehavior when we should perform the overscroll animation at the bottom.
+ */
+ fun Modifier.verticalNestedScrollToScene(
+ topBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
+ bottomBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
): 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..00e33e24c41e 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
@@ -172,7 +172,7 @@ internal class SceneTransitionLayoutImpl(
val width: Int
val height: Int
val state = state.transitionState
- if (state !is TransitionState.Transition || state.fromScene == state.toScene) {
+ if (state !is TransitionState.Transition) {
width = placeable.width
height = placeable.height
} else {
@@ -232,10 +232,7 @@ internal class SceneTransitionLayoutImpl(
is TransitionState.Idle -> drawContent()
is TransitionState.Transition -> {
// Don't draw scenes that are not ready yet.
- if (
- readyScenes.containsKey(key) ||
- state.fromScene == state.toScene
- ) {
+ 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..623725582a9d 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
@@ -39,11 +39,6 @@ class SceneTransitionLayoutState(initialScene: SceneKey) {
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)
}
@@ -71,32 +66,30 @@ 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
}
}
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 aa942e039856..e6224df649ca 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
@@ -58,16 +58,22 @@ class SceneGestureHandlerTest {
private val layoutState: SceneTransitionLayoutState =
SceneTransitionLayoutState(internalCurrentScene)
+ 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")
}
@@ -117,8 +123,8 @@ class SceneGestureHandlerTest {
fun nestedScrollConnection(nestedScrollBehavior: NestedScrollBehavior) =
SceneNestedScrollHandler(
gestureHandler = sceneGestureHandler,
- startBehavior = nestedScrollBehavior,
- endBehavior = nestedScrollBehavior,
+ topOrLeftBehavior = nestedScrollBehavior,
+ bottomOrRightBehavior = nestedScrollBehavior,
)
.connection
@@ -412,6 +418,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..eeda8d46adfa 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,18 +39,6 @@ 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)
@@ -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/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/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/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/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt
new file mode 100644
index 000000000000..30d1822b28da
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.pipeline.data.restoreprocessors
+
+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.coroutines.collectLastValue
+import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class WorkTileRestoreProcessorTest : SysuiTestCase() {
+
+ private val underTest = WorkTileRestoreProcessor()
+ @Test
+ fun restoreWithWorkTile_removeTracking() = runTest {
+ val removeTracking by collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER)))
+ runCurrent()
+
+ val restoreData =
+ RestoreData(
+ restoredTiles = listOf(TILE_SPEC),
+ restoredAutoAddedTiles = setOf(TILE_SPEC),
+ USER,
+ )
+
+ underTest.postProcessRestore(restoreData)
+
+ assertThat(removeTracking).isEqualTo(Unit)
+ }
+
+ @Test
+ fun restoreWithWorkTile_otherUser_noRemoveTracking() = runTest {
+ val removeTracking by
+ collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER + 1)))
+ runCurrent()
+
+ val restoreData =
+ RestoreData(
+ restoredTiles = listOf(TILE_SPEC),
+ restoredAutoAddedTiles = setOf(TILE_SPEC),
+ USER,
+ )
+
+ underTest.postProcessRestore(restoreData)
+
+ assertThat(removeTracking).isNull()
+ }
+
+ @Test
+ fun restoreWithoutWorkTile_noSignal() = runTest {
+ val removeTracking by collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER)))
+ runCurrent()
+
+ val restoreData =
+ RestoreData(
+ restoredTiles = emptyList(),
+ restoredAutoAddedTiles = emptySet(),
+ USER,
+ )
+
+ underTest.postProcessRestore(restoreData)
+
+ assertThat(removeTracking).isNull()
+ }
+
+ companion object {
+ private const val USER = 10
+ private val TILE_SPEC = TileSpec.Companion.create("work")
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
index adccc84e494b..c7e7845f206c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
@@ -25,6 +25,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
+import com.android.systemui.qs.pipeline.data.model.workTileRestoreProcessor
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -32,25 +37,28 @@ import com.android.systemui.qs.tiles.WorkModeTile
import com.android.systemui.settings.FakeUserTracker
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class WorkTileAutoAddableTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+
+ private val restoreProcessor: RestoreProcessor
+ get() = kosmos.workTileRestoreProcessor
+
private lateinit var userTracker: FakeUserTracker
private lateinit var underTest: WorkTileAutoAddable
@Before
fun setup() {
- MockitoAnnotations.initMocks(this)
-
userTracker =
FakeUserTracker(
_userId = USER_INFO_0.id,
@@ -58,7 +66,7 @@ class WorkTileAutoAddableTest : SysuiTestCase() {
_userProfiles = listOf(USER_INFO_0)
)
- underTest = WorkTileAutoAddable(userTracker)
+ underTest = WorkTileAutoAddable(userTracker, kosmos.workTileRestoreProcessor)
}
@Test
@@ -114,10 +122,80 @@ class WorkTileAutoAddableTest : SysuiTestCase() {
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Always)
}
+ @Test
+ fun restoreDataWithWorkTile_noCurrentManagedProfile_triggersRemove() = runTest {
+ val userId = 0
+ val signal by collectLastValue(underTest.autoAddSignal(userId))
+ runCurrent()
+
+ val restoreData = createRestoreWithWorkTile(userId)
+
+ restoreProcessor.postProcessRestore(restoreData)
+
+ assertThat(signal!!).isEqualTo(AutoAddSignal.RemoveTracking(SPEC))
+ }
+
+ @Test
+ fun restoreDataWithWorkTile_currentlyManagedProfile_doesntTriggerRemove() = runTest {
+ userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
+ val userId = 0
+ val signals by collectValues(underTest.autoAddSignal(userId))
+ runCurrent()
+
+ val restoreData = createRestoreWithWorkTile(userId)
+
+ restoreProcessor.postProcessRestore(restoreData)
+
+ assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC))
+ }
+
+ @Test
+ fun restoreDataWithoutWorkTile_noManagedProfile_doesntTriggerRemove() = runTest {
+ val userId = 0
+ val signals by collectValues(underTest.autoAddSignal(userId))
+ runCurrent()
+
+ val restoreData = createRestoreWithoutWorkTile(userId)
+
+ restoreProcessor.postProcessRestore(restoreData)
+
+ assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC))
+ }
+
+ @Test
+ fun restoreDataWithoutWorkTile_managedProfile_doesntTriggerRemove() = runTest {
+ userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
+ val userId = 0
+ val signals by collectValues(underTest.autoAddSignal(userId))
+ runCurrent()
+
+ val restoreData = createRestoreWithoutWorkTile(userId)
+
+ restoreProcessor.postProcessRestore(restoreData)
+
+ assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC))
+ }
+
companion object {
private val SPEC = TileSpec.create(WorkModeTile.TILE_SPEC)
private val USER_INFO_0 = UserInfo(0, "", FLAG_PRIMARY or FLAG_FULL)
private val USER_INFO_1 = UserInfo(1, "", FLAG_FULL)
private val USER_INFO_WORK = UserInfo(10, "", FLAG_PROFILE or FLAG_MANAGED_PROFILE)
+
+ private fun createRestoreWithWorkTile(userId: Int): RestoreData {
+ return RestoreData(
+ listOf(TileSpec.create("a"), SPEC, TileSpec.create("b")),
+ setOf(SPEC),
+ userId,
+ )
+ }
+
+ private fun createRestoreWithoutWorkTile(userId: Int): RestoreData {
+ return RestoreData(
+ listOf(TileSpec.create("a"), TileSpec.create("b")),
+ emptySet(),
+ userId,
+ )
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
index 41a7ec03408d..54b03a90229b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
@@ -183,6 +183,22 @@ class AutoAddInteractorTest : SysuiTestCase() {
assertThat(autoAddedTiles).contains(SPEC)
}
+ @Test
+ fun autoAddable_removeTrackingSignal_notRemovedButUnmarked() =
+ testScope.runTest {
+ autoAddRepository.markTileAdded(USER, SPEC)
+ val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER))
+ val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Always)
+
+ underTest = createInteractor(setOf(fakeAutoAddable))
+
+ fakeAutoAddable.sendRemoveTrackingSignal(USER)
+ runCurrent()
+
+ verify(currentTilesInteractor, never()).removeTiles(any())
+ assertThat(autoAddedTiles).doesNotContain(SPEC)
+ }
+
private fun createInteractor(autoAddables: Set<AutoAddable>): AutoAddInteractor {
return AutoAddInteractor(
autoAddables,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
index f73cab8a10a3..b2a9783d2e60 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
@@ -5,10 +5,15 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
import com.android.systemui.qs.pipeline.data.repository.FakeAutoAddRepository
import com.android.systemui.qs.pipeline.data.repository.FakeQSSettingsRestoredRepository
import com.android.systemui.qs.pipeline.data.repository.FakeTileSpecRepository
import com.android.systemui.qs.pipeline.data.repository.TilesSettingConverter
+import com.android.systemui.qs.pipeline.domain.interactor.RestoreReconciliationInteractorTest.TestableRestoreProcessor.Companion.POSTPROCESS
+import com.android.systemui.qs.pipeline.domain.interactor.RestoreReconciliationInteractorTest.TestableRestoreProcessor.Companion.PREPROCESS
+import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
+import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -17,7 +22,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.inOrder
@RunWith(AndroidJUnit4::class)
@SmallTest
@@ -28,6 +33,9 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() {
private val qsSettingsRestoredRepository = FakeQSSettingsRestoredRepository()
+ private val restoreProcessor: TestableRestoreProcessor = TestableRestoreProcessor()
+ private val qsLogger: QSPipelineLogger = mock()
+
private lateinit var underTest: RestoreReconciliationInteractor
private val testDispatcher = StandardTestDispatcher()
@@ -35,13 +43,13 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() {
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
-
underTest =
RestoreReconciliationInteractor(
tileSpecRepository,
autoAddRepository,
qsSettingsRestoredRepository,
+ setOf(restoreProcessor),
+ qsLogger,
testScope.backgroundScope,
testDispatcher
)
@@ -85,6 +93,44 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() {
assertThat(autoAdd).isEqualTo(expectedAutoAdd.toTilesSet())
}
+ @Test
+ fun restoreProcessorsCalled() =
+ testScope.runTest {
+ val user = 10
+
+ val restoredSpecs = "a,c,d,f"
+ val restoredAutoAdded = "d,e"
+
+ val restoreData =
+ RestoreData(
+ restoredSpecs.toTilesList(),
+ restoredAutoAdded.toTilesSet(),
+ user,
+ )
+
+ qsSettingsRestoredRepository.onDataRestored(restoreData)
+ runCurrent()
+
+ assertThat(restoreProcessor.calls).containsExactly(PREPROCESS, POSTPROCESS).inOrder()
+ }
+
+ private class TestableRestoreProcessor : RestoreProcessor {
+ val calls = mutableListOf<Any>()
+
+ override suspend fun preProcessRestore(restoreData: RestoreData) {
+ calls.add(PREPROCESS)
+ }
+
+ override suspend fun postProcessRestore(restoreData: RestoreData) {
+ calls.add(POSTPROCESS)
+ }
+
+ companion object {
+ val PREPROCESS = Any()
+ val POSTPROCESS = Any()
+ }
+ }
+
companion object {
private fun String.toTilesList() = TilesSettingConverter.toTilesList(this)
private fun String.toTilesSet() = TilesSettingConverter.toTilesSet(this)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/WorkProfileAutoAddedAfterRestoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/WorkProfileAutoAddedAfterRestoreTest.kt
new file mode 100644
index 000000000000..96d57743e2ee
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/WorkProfileAutoAddedAfterRestoreTest.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.qs.pipeline.domain.interactor
+
+import android.content.pm.UserInfo
+import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.android.systemui.Flags.FLAG_QS_NEW_PIPELINE
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.FakeQSFactory
+import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.data.repository.fakeRestoreRepository
+import com.android.systemui.qs.pipeline.data.repository.fakeTileSpecRepository
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.qsTileFactory
+import com.android.systemui.settings.fakeUserTracker
+import com.android.systemui.settings.userTracker
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+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
+
+/**
+ * This integration test is for testing the solution to b/314781280. In particular, there are two
+ * issues we want to verify after a restore of a device with a work profile and a work mode tile:
+ * * When the work profile is re-enabled in the target device, it is auto-added.
+ * * The tile is auto-added in the same position that it was in the restored device.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class WorkProfileAutoAddedAfterRestoreTest : SysuiTestCase() {
+
+ private val kosmos = Kosmos().apply { fakeUserTracker.set(listOf(USER_0_INFO), 0) }
+ // Getter here so it can change when there is a managed profile.
+ private val workTileAvailable: Boolean
+ get() = hasManagedProfile()
+ private val currentUser: Int
+ get() = kosmos.userTracker.userId
+
+ private val testScope: TestScope
+ get() = kosmos.testScope
+
+ @Before
+ fun setUp() {
+ mSetFlagsRule.enableFlags(FLAG_QS_NEW_PIPELINE)
+
+ kosmos.qsTileFactory = FakeQSFactory(::tileCreator)
+ kosmos.restoreReconciliationInteractor.start()
+ kosmos.autoAddInteractor.init(kosmos.currentTilesInteractor)
+ }
+
+ @Test
+ fun workTileRestoredAndPreviouslyAutoAdded_notAvailable_willBeAutoaddedInCorrectPosition() =
+ testScope.runTest {
+ val tiles by collectLastValue(kosmos.currentTilesInteractor.currentTiles)
+
+ // Set up
+ val currentTiles = listOf("a".toTileSpec())
+ kosmos.fakeTileSpecRepository.setTiles(currentUser, currentTiles)
+
+ val restoredTiles =
+ listOf(WORK_TILE_SPEC) + listOf("b", "c", "d").map { it.toTileSpec() }
+ val restoredAutoAdded = setOf(WORK_TILE_SPEC)
+
+ val restoreData = RestoreData(restoredTiles, restoredAutoAdded, currentUser)
+
+ // WHEN we restore tiles that auto-added the WORK tile and it's not available (there
+ // are no managed profiles)
+ kosmos.fakeRestoreRepository.onDataRestored(restoreData)
+
+ // THEN the work tile is not part of the current tiles
+ assertThat(tiles!!).hasSize(3)
+ assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC)
+
+ // WHEN we add a work profile
+ createManagedProfileAndAdd()
+
+ // THEN the work profile is added in the correct place
+ assertThat(tiles!!.first().spec).isEqualTo(WORK_TILE_SPEC)
+ }
+
+ @Test
+ fun workTileNotRestoredAndPreviouslyAutoAdded_wontBeAutoAddedWhenWorkProfileIsAdded() =
+ testScope.runTest {
+ val tiles by collectLastValue(kosmos.currentTilesInteractor.currentTiles)
+
+ // Set up
+ val currentTiles = listOf("a".toTileSpec())
+ kosmos.fakeTileSpecRepository.setTiles(currentUser, currentTiles)
+ runCurrent()
+
+ val restoredTiles = listOf("b", "c", "d").map { it.toTileSpec() }
+ val restoredAutoAdded = setOf(WORK_TILE_SPEC)
+
+ val restoreData = RestoreData(restoredTiles, restoredAutoAdded, currentUser)
+
+ // WHEN we restore tiles that auto-added the WORK tile
+ kosmos.fakeRestoreRepository.onDataRestored(restoreData)
+
+ // THEN the work tile is not part of the current tiles
+ assertThat(tiles!!).hasSize(3)
+ assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC)
+
+ // WHEN we add a work profile
+ createManagedProfileAndAdd()
+
+ // THEN the work profile is not added because the user had manually removed it in the
+ // past
+ assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC)
+ }
+
+ private fun tileCreator(spec: String): QSTile {
+ return if (spec == WORK_TILE_SPEC.spec) {
+ FakeQSTile(currentUser, workTileAvailable)
+ } else {
+ FakeQSTile(currentUser)
+ }
+ }
+
+ private fun hasManagedProfile(): Boolean {
+ return kosmos.userTracker.userProfiles.any { it.isManagedProfile }
+ }
+
+ private fun TestScope.createManagedProfileAndAdd() {
+ kosmos.fakeUserTracker.set(
+ listOf(USER_0_INFO, MANAGED_USER_INFO),
+ 0,
+ )
+ runCurrent()
+ }
+
+ private companion object {
+ val WORK_TILE_SPEC = "work".toTileSpec()
+ val USER_0_INFO =
+ UserInfo(
+ 0,
+ "zero",
+ "",
+ UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
+ )
+ val MANAGED_USER_INFO =
+ UserInfo(
+ 10,
+ "ten-managed",
+ "",
+ 0,
+ UserManager.USER_TYPE_PROFILE_MANAGED,
+ )
+
+ fun String.toTileSpec() = TileSpec.create(this)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt
index 2b744ac8398a..00405d0a07e7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.alarm.domain
import android.app.AlarmManager
+import android.graphics.drawable.TestStubDrawable
import android.widget.Switch
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -40,7 +41,14 @@ class AlarmTileMapperTest : SysuiTestCase() {
private val kosmos = Kosmos()
private val alarmTileConfig = kosmos.qsAlarmTileConfig
// Using lazy (versus =) to make sure we override the right context -- see b/311612168
- private val mapper by lazy { AlarmTileMapper(context.orCreateTestableResources.resources) }
+ private val mapper by lazy {
+ AlarmTileMapper(
+ context.orCreateTestableResources
+ .apply { addOverride(R.drawable.ic_alarm, TestStubDrawable()) }
+ .resources,
+ context.theme
+ )
+ }
@Test
fun notAlarmSet() {
@@ -100,7 +108,7 @@ class AlarmTileMapperTest : SysuiTestCase() {
): QSTileState {
val label = context.getString(R.string.status_bar_alarm)
return QSTileState(
- { Icon.Resource(R.drawable.ic_alarm, null) },
+ { Icon.Loaded(context.getDrawable(R.drawable.ic_alarm)!!, null) },
label,
activationState,
secondaryLabel,
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/flashlight/domain/FlashlightMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt
index 7b2ac90b9766..b60f483cccbb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.flashlight.domain
+import android.graphics.drawable.TestStubDrawable
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -35,7 +36,17 @@ import org.junit.runner.RunWith
class FlashlightMapperTest : SysuiTestCase() {
private val kosmos = Kosmos()
private val qsTileConfig = kosmos.qsFlashlightTileConfig
- private val mapper by lazy { FlashlightMapper(context.orCreateTestableResources.resources) }
+ private val mapper by lazy {
+ FlashlightMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(R.drawable.qs_flashlight_icon_off, TestStubDrawable())
+ addOverride(R.drawable.qs_flashlight_icon_on, TestStubDrawable())
+ }
+ .resources,
+ context.theme
+ )
+ }
@Test
fun mapsDisabledDataToInactiveState() {
@@ -56,20 +67,20 @@ class FlashlightMapperTest : SysuiTestCase() {
@Test
fun mapsEnabledDataToOnIconState() {
- val expectedIcon = Icon.Resource(R.drawable.qs_flashlight_icon_on, null)
-
val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(true))
+ val expectedIcon =
+ Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_on)!!, null)
val actualIcon = tileState.icon()
assertThat(actualIcon).isEqualTo(expectedIcon)
}
@Test
fun mapsDisabledDataToOffIconState() {
- val expectedIcon = Icon.Resource(R.drawable.qs_flashlight_icon_off, null)
-
val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(false))
+ val expectedIcon =
+ Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, null)
val actualIcon = tileState.icon()
assertThat(actualIcon).isEqualTo(expectedIcon)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt
index 8791877f8863..ea74a4c0d398 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.location.domain
+import android.graphics.drawable.TestStubDrawable
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -36,7 +37,17 @@ class LocationTileMapperTest : SysuiTestCase() {
private val kosmos = Kosmos()
private val qsTileConfig = kosmos.qsLocationTileConfig
- private val mapper by lazy { LocationTileMapper(context.orCreateTestableResources.resources) }
+ private val mapper by lazy {
+ LocationTileMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(R.drawable.qs_location_icon_off, TestStubDrawable())
+ addOverride(R.drawable.qs_location_icon_on, TestStubDrawable())
+ }
+ .resources,
+ context.theme
+ )
+ }
@Test
fun mapsDisabledDataToInactiveState() {
@@ -56,20 +67,18 @@ class LocationTileMapperTest : SysuiTestCase() {
@Test
fun mapsEnabledDataToOnIconState() {
- val expectedIcon = Icon.Resource(R.drawable.qs_location_icon_on, null)
-
val tileState: QSTileState = mapper.map(qsTileConfig, LocationTileModel(true))
+ val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_location_icon_on)!!, null)
val actualIcon = tileState.icon()
Truth.assertThat(actualIcon).isEqualTo(expectedIcon)
}
@Test
fun mapsDisabledDataToOffIconState() {
- val expectedIcon = Icon.Resource(R.drawable.qs_location_icon_off, null)
-
val tileState: QSTileState = mapper.map(qsTileConfig, LocationTileModel(false))
+ val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_location_icon_off)!!, null)
val actualIcon = tileState.icon()
Truth.assertThat(actualIcon).isEqualTo(expectedIcon)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt
index d1824129590b..d162c778f607 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.saver.domain
+import android.graphics.drawable.TestStubDrawable
import android.widget.Switch
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -37,7 +38,17 @@ class DataSaverTileMapperTest : SysuiTestCase() {
private val dataSaverTileConfig = kosmos.qsDataSaverTileConfig
// Using lazy (versus =) to make sure we override the right context -- see b/311612168
- private val mapper by lazy { DataSaverTileMapper(context.orCreateTestableResources.resources) }
+ private val mapper by lazy {
+ DataSaverTileMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(R.drawable.qs_data_saver_icon_off, TestStubDrawable())
+ addOverride(R.drawable.qs_data_saver_icon_on, TestStubDrawable())
+ }
+ .resources,
+ context.theme
+ )
+ }
@Test
fun activeStateMatchesEnabledModel() {
@@ -80,7 +91,7 @@ class DataSaverTileMapperTest : SysuiTestCase() {
else context.resources.getStringArray(R.array.tile_states_saver)[0]
return QSTileState(
- { Icon.Resource(iconRes, null) },
+ { Icon.Loaded(context.getDrawable(iconRes)!!, null) },
label,
activationState,
secondaryLabel,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt
index 87f50090e58b..a9776068b20c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.uimodenight.domain
import android.app.UiModeManager
+import android.graphics.drawable.TestStubDrawable
import android.text.TextUtils
import android.view.View
import android.widget.Switch
@@ -41,7 +42,15 @@ class UiModeNightTileMapperTest : SysuiTestCase() {
private val qsTileConfig = kosmos.qsUiModeNightTileConfig
private val mapper by lazy {
- UiModeNightTileMapper(context.orCreateTestableResources.resources)
+ UiModeNightTileMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(R.drawable.qs_light_dark_theme_icon_off, TestStubDrawable())
+ addOverride(R.drawable.qs_light_dark_theme_icon_on, TestStubDrawable())
+ }
+ .resources,
+ context.theme
+ )
}
private fun createUiNightModeTileState(
@@ -60,7 +69,7 @@ class UiModeNightTileMapperTest : SysuiTestCase() {
expandedAccessibilityClass: KClass<out View>? = Switch::class,
): QSTileState {
return QSTileState(
- { Icon.Resource(iconRes, null) },
+ { Icon.Loaded(context.getDrawable(iconRes)!!, null) },
label,
activationState,
secondaryLabel,
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/drawable/bouncer_password_text_view_focused_background.xml b/packages/SystemUI/res-keyguard/drawable/bouncer_password_text_view_focused_background.xml
deleted file mode 100644
index 02e10cd4ad7c..000000000000
--- a/packages/SystemUI/res-keyguard/drawable/bouncer_password_text_view_focused_background.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true">
- <shape android:shape="rectangle">
- <corners android:radius="16dp" />
- <stroke android:width="3dp"
- android:color="@color/bouncer_password_focus_color" />
- </shape>
- </item>
-</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
index 0b35559148af..66c54f2a668e 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
@@ -23,7 +23,7 @@
android:layout_marginTop="@dimen/keyguard_lock_padding"
android:importantForAccessibility="no"
android:ellipsize="marquee"
- android:focusable="false"
+ android:focusable="true"
android:gravity="center"
android:singleLine="true" />
</merge>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 6e6709f94abb..88f7bcd5d907 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -76,7 +76,6 @@
</style>
<style name="Widget.TextView.Password" parent="@android:style/Widget.TextView">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:background">@drawable/bouncer_password_text_view_focused_background</item>
<item name="android:gravity">center</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
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/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index a22fd18fc2c0..bcc3c83b4560 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -93,9 +93,6 @@
<color name="qs_user_switcher_selected_avatar_icon_color">#202124</color>
<!-- Color of background circle of user avatars in quick settings user switcher -->
<color name="qs_user_switcher_avatar_background">#3C4043</color>
- <!-- Color of border for keyguard password input when focused -->
- <color name="bouncer_password_focus_color">@*android:color/system_secondary_dark</color>
-
<!-- Accessibility floating menu -->
<color name="accessibility_floating_menu_background">#B3000000</color> <!-- 70% -->
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 462fc95b8cd1..5f6a39a91b8b 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -56,8 +56,6 @@
<color name="kg_user_switcher_restricted_avatar_icon_color">@color/GM2_grey_600</color>
<!-- Color of background circle of user avatars in keyguard user switcher -->
<color name="user_avatar_color_bg">?android:attr/colorBackgroundFloating</color>
- <!-- Color of border for keyguard password input when focused -->
- <color name="bouncer_password_focus_color">@*android:color/system_secondary_light</color>
<!-- Icon color for user avatars in user switcher quick settings -->
<color name="qs_user_switcher_avatar_icon_color">#3C4043</color>
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..0169f59a5a20 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
@@ -49,6 +49,7 @@ public final class InteractionJankMonitorWrapper {
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;
+ public static final int CUJ_SEARCH_QSB_OPEN = Cuj.CUJ_LAUNCHER_SEARCH_QSB_OPEN;
@IntDef({
CUJ_APP_LAUNCH_FROM_RECENTS,
@@ -66,6 +67,7 @@ public final class InteractionJankMonitorWrapper {
CUJ_CLOSE_ALL_APPS_TO_HOME,
CUJ_OPEN_SEARCH_RESULT,
CUJ_LAUNCHER_UNFOLD_ANIM,
+ CUJ_SEARCH_QSB_OPEN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 9764de1993e5..36fe75f69a45 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -168,6 +168,7 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
// Set selected property on so the view can send accessibility events.
mPasswordEntry.setSelected(true);
+ mPasswordEntry.setDefaultFocusHighlightEnabled(false);
mOkButton = findViewById(R.id.key_enter);
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/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/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/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/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index d5b95d6721f9..5ec51f4c3dad 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -16,6 +16,12 @@
package com.android.systemui.flags
+import com.android.server.notification.Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS
+import com.android.server.notification.Flags.FLAG_POLITE_NOTIFICATIONS
+import com.android.server.notification.Flags.FLAG_VIBRATE_WHILE_UNLOCKED
+import com.android.server.notification.Flags.crossAppPoliteNotifications
+import com.android.server.notification.Flags.politeNotifications
+import com.android.server.notification.Flags.vibrateWhileUnlocked
import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.dagger.SysUISingleton
@@ -36,5 +42,14 @@ class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, ha
val keyguardBottomAreaRefactor = FlagToken(
FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR, keyguardBottomAreaRefactor())
KeyguardShadeMigrationNssl.token dependsOn keyguardBottomAreaRefactor
+
+ val crossAppPoliteNotifToken =
+ FlagToken(FLAG_CROSS_APP_POLITE_NOTIFICATIONS, crossAppPoliteNotifications())
+ val politeNotifToken = FlagToken(FLAG_POLITE_NOTIFICATIONS, politeNotifications())
+ crossAppPoliteNotifToken dependsOn politeNotifToken
+
+ val vibrateWhileUnlockedToken =
+ FlagToken(FLAG_VIBRATE_WHILE_UNLOCKED, vibrateWhileUnlocked())
+ vibrateWhileUnlockedToken dependsOn politeNotifToken
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b753ff742100..b1d4587c20d8 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -111,7 +111,7 @@ object Flags {
// TODO(b/301955929)
@JvmField
val NOTIF_LS_BACKGROUND_THREAD =
- unreleasedFlag("notification_lockscreen_mgr_bg_thread", teamfood = true)
+ releasedFlag("notification_lockscreen_mgr_bg_thread")
// 200 - keyguard/lockscreen
// ** Flag retired **
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b7260f2b2b94..57f3b7071d1d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -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;
@@ -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);
@@ -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/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index b51edab6dfe8..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
@@ -160,6 +160,9 @@ interface KeyguardRepository {
/** Last point that [KeyguardRootView] was tapped */
val lastRootViewTapPosition: MutableStateFlow<Point?>
+ /** Is the ambient indication area visible? */
+ val ambientIndicationVisible: MutableStateFlow<Boolean>
+
/** Observable for the [StatusBarState] */
val statusBarState: StateFlow<StatusBarState>
@@ -189,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>
@@ -236,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. */
@@ -266,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()
@@ -423,6 +453,8 @@ constructor(
override val lastRootViewTapPosition: MutableStateFlow<Point?> = MutableStateFlow(null)
+ override val ambientIndicationVisible: MutableStateFlow<Boolean> = MutableStateFlow(false)
+
override val isDreamingWithOverlay: Flow<Boolean> =
conflatedCallbackFlow {
val callback =
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 c12efe875b0b..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
@@ -174,6 +174,9 @@ constructor(
/** Last point that [KeyguardRootView] view was tapped */
val lastRootViewTapPosition: Flow<Point?> = repository.lastRootViewTapPosition.asStateFlow()
+ /** Is the ambient indication area visible? */
+ val ambientIndicationVisible: Flow<Boolean> = repository.ambientIndicationVisible.asStateFlow()
+
/** Whether the primary bouncer is showing or not. */
val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerShow
@@ -311,6 +314,14 @@ constructor(
repository.lastRootViewTapPosition.value = point
}
+ fun setAmbientIndicationVisible(isVisible: Boolean) {
+ 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/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/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 1d4520ff8f03..26dace00ad76 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -180,7 +180,9 @@ constructor(
goneToAodTransitionViewModel
.enterFromTopTranslationY(enterFromTopAmount)
.onStart { emit(0f) },
- occludedToLockscreenTransitionViewModel.lockscreenTranslationY,
+ occludedToLockscreenTransitionViewModel.lockscreenTranslationY.onStart {
+ emit(0f)
+ },
) {
keyguardTransitionY,
burnInTranslationY,
@@ -193,6 +195,7 @@ constructor(
occludedToLockscreenTransitionTranslationY
}
}
+ .distinctUntilChanged()
val translationX: Flow<Float> = burnIn().map { it.translationX.toFloat() }
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/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/privacy/PrivacyDialogControllerV2.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogControllerV2.kt
index fdc70a83e8b1..76ef8a2b813c 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogControllerV2.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogControllerV2.kt
@@ -278,7 +278,12 @@ class PrivacyDialogControllerV2(
d.setShowForAllUsers(true)
d.addOnDismissListener(onDialogDismissed)
if (view != null) {
- dialogLaunchAnimator.showFromView(d, view)
+ val controller = getPrivacyDialogController(view)
+ if (controller == null) {
+ d.show()
+ } else {
+ dialogLaunchAnimator.show(d, controller)
+ }
} else {
d.show()
}
@@ -291,6 +296,13 @@ class PrivacyDialogControllerV2(
}
}
+ private fun getPrivacyDialogController(source: View): DialogLaunchAnimator.Controller? {
+ val delegate = DialogLaunchAnimator.Controller.fromView(source) ?: return null
+ return object : DialogLaunchAnimator.Controller by delegate {
+ override fun shouldAnimateExit() = false
+ }
+ }
+
/** Dismisses the dialog */
fun dismissDialog() {
dialog?.dismiss()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
index b50798e59953..4bad45f19673 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
@@ -20,6 +20,7 @@ import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
import com.android.systemui.qs.pipeline.data.repository.DefaultTilesQSHostRepository
import com.android.systemui.qs.pipeline.data.repository.DefaultTilesRepository
import com.android.systemui.qs.pipeline.data.repository.InstalledTilesComponentRepository
@@ -39,14 +40,17 @@ import dagger.Module
import dagger.Provides
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
+import dagger.multibindings.Multibinds
-@Module(includes = [QSAutoAddModule::class])
+@Module(includes = [QSAutoAddModule::class, RestoreProcessorsModule::class])
abstract class QSPipelineModule {
/** Implementation for [TileSpecRepository] */
@Binds
abstract fun provideTileSpecRepository(impl: TileSpecSettingsRepository): TileSpecRepository
+ @Multibinds abstract fun provideRestoreProcessors(): Set<RestoreProcessor>
+
@Binds
abstract fun provideDefaultTilesRepository(
impl: DefaultTilesQSHostRepository
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/RestoreProcessorsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/RestoreProcessorsModule.kt
new file mode 100644
index 000000000000..e970c84d166f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/RestoreProcessorsModule.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.pipeline.dagger
+
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
+import com.android.systemui.qs.pipeline.data.restoreprocessors.WorkTileRestoreProcessor
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+
+@Module
+interface RestoreProcessorsModule {
+
+ @Binds
+ @IntoSet
+ fun bindWorkTileRestoreProcessor(impl: WorkTileRestoreProcessor): RestoreProcessor
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessor.kt
new file mode 100644
index 000000000000..8f7de1976b36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessor.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.pipeline.data.model
+
+/**
+ * Perform processing of the [RestoreData] before or after it's applied to repositories.
+ *
+ * The order in which the restore processors are applied in not deterministic.
+ *
+ * In order to declare a restore processor, add it in [RestoreProcessingModule] using
+ *
+ * ```
+ * @Binds
+ * @IntoSet
+ * ``
+ */
+interface RestoreProcessor {
+
+ /** Should be called before applying the restore to the necessary repositories */
+ suspend fun preProcessRestore(restoreData: RestoreData) {}
+
+ /** Should be called after requesting the repositories to update. */
+ suspend fun postProcessRestore(restoreData: RestoreData) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt
index 7998dfbe3f92..d40f3f4db5f3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt
@@ -20,9 +20,8 @@ import android.util.SparseArray
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.pipeline.data.model.RestoreData
import com.android.systemui.qs.pipeline.shared.TileSpec
-import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
-import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.Flow
/** Repository to track what QS tiles have been auto-added */
interface AutoAddRepository {
@@ -49,8 +48,9 @@ interface AutoAddRepository {
@SysUISingleton
class AutoAddSettingRepository
@Inject
-constructor(private val userAutoAddRepositoryFactory: UserAutoAddRepository.Factory) :
- AutoAddRepository {
+constructor(
+ private val userAutoAddRepositoryFactory: UserAutoAddRepository.Factory,
+) : AutoAddRepository {
private val userAutoAddRepositories = SparseArray<UserAutoAddRepository>()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt
index 6cee1161a104..e718eea09665 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt
@@ -10,6 +10,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.data.repository.QSSettingsRestoredRepository.Companion.BUFFER_CAPACITY
import com.android.systemui.qs.pipeline.data.repository.TilesSettingConverter.toTilesList
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
import javax.inject.Inject
@@ -28,6 +29,14 @@ import kotlinx.coroutines.flow.shareIn
/** Provides restored data (from Backup and Restore) for Quick Settings pipeline */
interface QSSettingsRestoredRepository {
val restoreData: Flow<RestoreData>
+
+ companion object {
+ // This capacity is the number of restore data that we will keep buffered in the shared
+ // flow. It is unlikely that at any given time there would be this many restores being
+ // processed by consumers, but just in case that a couple of users are restored at the
+ // same time and they need to be replayed for the consumers of the flow.
+ const val BUFFER_CAPACITY = 10
+ }
}
@SysUISingleton
@@ -86,11 +95,6 @@ constructor(
private companion object {
private const val TAG = "QSSettingsRestoredBroadcastRepository"
- // This capacity is the number of restore data that we will keep buffered in the shared
- // flow. It is unlikely that at any given time there would be this many restores being
- // processed by consumers, but just in case that a couple of users are restored at the
- // same time and they need to be replayed for the consumers of the flow.
- private const val BUFFER_CAPACITY = 10
private val INTENT_FILTER = IntentFilter(Intent.ACTION_SETTING_RESTORED)
private const val TILES_SETTING = Settings.Secure.QS_TILES
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessor.kt
new file mode 100644
index 000000000000..7376aa90883f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessor.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.pipeline.data.restoreprocessors
+
+import android.os.UserHandle
+import android.util.SparseIntArray
+import androidx.annotation.GuardedBy
+import androidx.core.util.getOrDefault
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
+import com.android.systemui.qs.pipeline.data.repository.QSSettingsRestoredRepository
+import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.WorkModeTile
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+
+/**
+ * Processor for restore data for work tile.
+ *
+ * It will indicate when auto-add tracking may be removed for a user. This may be necessary if the
+ * tile will be destroyed due to being not available, but needs to be added once work profile is
+ * enabled (after restore), in the same position as it was in the restored data.
+ */
+@SysUISingleton
+class WorkTileRestoreProcessor @Inject constructor() : RestoreProcessor {
+
+ @GuardedBy("lastRestorePosition") private val lastRestorePosition = SparseIntArray()
+
+ private val _removeTrackingForUser =
+ MutableSharedFlow<Int>(extraBufferCapacity = QSSettingsRestoredRepository.BUFFER_CAPACITY)
+
+ /**
+ * Flow indicating that we may need to remove auto-add tracking for the work tile for a given
+ * user.
+ */
+ fun removeTrackingForUser(userHandle: UserHandle): Flow<Unit> {
+ return _removeTrackingForUser.filter { it == userHandle.identifier }.map {}
+ }
+
+ override suspend fun postProcessRestore(restoreData: RestoreData) {
+ if (TILE_SPEC in restoreData.restoredTiles) {
+ synchronized(lastRestorePosition) {
+ lastRestorePosition.put(
+ restoreData.userId,
+ restoreData.restoredTiles.indexOf(TILE_SPEC)
+ )
+ }
+ _removeTrackingForUser.emit(restoreData.userId)
+ }
+ }
+
+ fun pollLastPosition(userId: Int): Int {
+ return synchronized(lastRestorePosition) {
+ lastRestorePosition.getOrDefault(userId, TileSpecRepository.POSITION_AT_END).also {
+ lastRestorePosition.delete(userId)
+ }
+ }
+ }
+
+ companion object {
+ private val TILE_SPEC = TileSpec.create(WorkModeTile.TILE_SPEC)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt
index 5e3c34841c50..b22119966460 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt
@@ -17,8 +17,10 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
import android.content.pm.UserInfo
+import android.os.UserHandle
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.data.restoreprocessors.WorkTileRestoreProcessor
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
@@ -28,6 +30,8 @@ import com.android.systemui.settings.UserTracker
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.mapNotNull
+import kotlinx.coroutines.flow.merge
/**
* [AutoAddable] for [WorkModeTile.TILE_SPEC].
@@ -36,17 +40,37 @@ import kotlinx.coroutines.flow.Flow
* signal to remove it if there is not.
*/
@SysUISingleton
-class WorkTileAutoAddable @Inject constructor(private val userTracker: UserTracker) : AutoAddable {
+class WorkTileAutoAddable
+@Inject
+constructor(
+ private val userTracker: UserTracker,
+ private val workTileRestoreProcessor: WorkTileRestoreProcessor,
+) : AutoAddable {
private val spec = TileSpec.create(WorkModeTile.TILE_SPEC)
override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
- return conflatedCallbackFlow {
+ val removeTrackingDueToRestore: Flow<AutoAddSignal> =
+ workTileRestoreProcessor.removeTrackingForUser(UserHandle.of(userId)).mapNotNull {
+ val profiles = userTracker.userProfiles
+ if (profiles.any { it.id == userId } && !profiles.any { it.isManagedProfile }) {
+ // Only remove auto-added if there are no managed profiles for this user
+ AutoAddSignal.RemoveTracking(spec)
+ } else {
+ null
+ }
+ }
+ val signalsFromCallback = conflatedCallbackFlow {
fun maybeSend(profiles: List<UserInfo>) {
if (profiles.any { it.id == userId }) {
// We are looking at the profiles of the correct user.
if (profiles.any { it.isManagedProfile }) {
- trySend(AutoAddSignal.Add(spec))
+ trySend(
+ AutoAddSignal.Add(
+ spec,
+ workTileRestoreProcessor.pollLastPosition(userId),
+ )
+ )
} else {
trySend(AutoAddSignal.Remove(spec))
}
@@ -65,6 +89,7 @@ class WorkTileAutoAddable @Inject constructor(private val userTracker: UserTrack
awaitClose { userTracker.removeCallback(callback) }
}
+ return merge(removeTrackingDueToRestore, signalsFromCallback)
}
override val autoAddTracking = AutoAddTracking.Always
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt
index b74739322fcd..cde38359a871 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt
@@ -103,6 +103,10 @@ constructor(
qsPipelineLogger.logTileAutoRemoved(userId, signal.spec)
repository.unmarkTileAdded(userId, signal.spec)
}
+ is AutoAddSignal.RemoveTracking -> {
+ qsPipelineLogger.logTileUnmarked(userId, signal.spec)
+ repository.unmarkTileAdded(userId, signal.spec)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractor.kt
index 9844903eff26..a5be14ec3776 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractor.kt
@@ -3,14 +3,15 @@ package com.android.systemui.qs.pipeline.domain.interactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
import com.android.systemui.qs.pipeline.data.repository.AutoAddRepository
import com.android.systemui.qs.pipeline.data.repository.QSSettingsRestoredRepository
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
+import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.take
@@ -33,6 +34,8 @@ constructor(
private val tileSpecRepository: TileSpecRepository,
private val autoAddRepository: AutoAddRepository,
private val qsSettingsRestoredRepository: QSSettingsRestoredRepository,
+ private val restoreProcessors: Set<@JvmSuppressWildcards RestoreProcessor>,
+ private val qsPipelineLogger: QSPipelineLogger,
@Application private val applicationScope: CoroutineScope,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) {
@@ -40,14 +43,30 @@ constructor(
@OptIn(ExperimentalCoroutinesApi::class)
fun start() {
applicationScope.launch(backgroundDispatcher) {
- qsSettingsRestoredRepository.restoreData.flatMapConcat { data ->
- autoAddRepository.autoAddedTiles(data.userId)
- .take(1)
- .map { tiles -> data to tiles }
- }.collect { (restoreData, autoAdded) ->
- tileSpecRepository.reconcileRestore(restoreData, autoAdded)
- autoAddRepository.reconcileRestore(restoreData)
- }
+ qsSettingsRestoredRepository.restoreData
+ .flatMapConcat { data ->
+ autoAddRepository.autoAddedTiles(data.userId).take(1).map { tiles ->
+ data to tiles
+ }
+ }
+ .collect { (restoreData, autoAdded) ->
+ restoreProcessors.forEach {
+ it.preProcessRestore(restoreData)
+ qsPipelineLogger.logRestoreProcessorApplied(
+ it::class.simpleName,
+ QSPipelineLogger.RestorePreprocessorStep.PREPROCESSING,
+ )
+ }
+ tileSpecRepository.reconcileRestore(restoreData, autoAdded)
+ autoAddRepository.reconcileRestore(restoreData)
+ restoreProcessors.forEach {
+ it.postProcessRestore(restoreData)
+ qsPipelineLogger.logRestoreProcessorApplied(
+ it::class.simpleName,
+ QSPipelineLogger.RestorePreprocessorStep.POSTPROCESSING,
+ )
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt
index ed7b8bd4c2f4..8263680d7fad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt
@@ -34,4 +34,9 @@ sealed interface AutoAddSignal {
data class Remove(
override val spec: TileSpec,
) : AutoAddSignal
+
+ /** Signal for remove the auto-add marker from the tile, but not remove the tile */
+ data class RemoveTracking(
+ override val spec: TileSpec,
+ ) : AutoAddSignal
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
index bca86c9ee8af..7d2c6c8f70fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
@@ -209,6 +209,18 @@ constructor(
)
}
+ fun logTileUnmarked(userId: Int, spec: TileSpec) {
+ tileAutoAddLogBuffer.log(
+ AUTO_ADD_TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = userId
+ str1 = spec.toString()
+ },
+ { "Tile $str1 unmarked as auto-added for user $int1" }
+ )
+ }
+
fun logSettingsRestored(restoreData: RestoreData) {
restoreLogBuffer.log(
RESTORE_TAG,
@@ -226,6 +238,21 @@ constructor(
)
}
+ fun logRestoreProcessorApplied(
+ restoreProcessorClassName: String?,
+ step: RestorePreprocessorStep,
+ ) {
+ restoreLogBuffer.log(
+ RESTORE_TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = restoreProcessorClassName
+ str2 = step.name
+ },
+ { "Restore $str2 processed by $str1" }
+ )
+ }
+
/** Reasons for destroying an existing tile. */
enum class TileDestroyedReason(val readable: String) {
TILE_REMOVED("Tile removed from current set"),
@@ -234,4 +261,9 @@ constructor(
EXISTING_TILE_NOT_AVAILABLE("Existing tile not available"),
TILE_NOT_PRESENT_IN_NEW_USER("Tile not present in new user"),
}
+
+ enum class RestorePreprocessorStep {
+ PREPROCESSING,
+ POSTPROCESSING
+ }
}
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..0434b2d89e32 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,11 @@ 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.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 +58,11 @@ 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,
) :
QSTileImpl<QSTile.BooleanState>(
host,
@@ -76,11 +88,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) {
+ 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/interactor/QSTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt
index 09d7a1f7142d..17b78ebf106c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt
@@ -24,7 +24,7 @@ interface QSTileUserActionInteractor<DATA_TYPE> {
* [QSTileInput.data]. It's guaranteed that [QSTileInput.userId] is the same as the id passed to
* [QSTileDataInteractor] to get [QSTileInput.data].
*
- * It's safe to run long running computations inside this function in this.
+ * It's safe to run long running computations inside this function.
*/
@WorkerThread suspend fun handleInput(input: QSTileInput<DATA_TYPE>)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
index 4a34276671c1..b325b4daeb81 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles.di
+import android.content.Context
+import android.content.res.Resources.Theme
import com.android.systemui.qs.external.CustomTileStatePersister
import com.android.systemui.qs.external.CustomTileStatePersisterImpl
import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
@@ -27,6 +29,7 @@ import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProviderImpl
import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
import dagger.Binds
import dagger.Module
+import dagger.Provides
import dagger.multibindings.Multibinds
/** Module listing subcomponents */
@@ -57,4 +60,9 @@ interface QSTilesModule {
@Binds
fun bindCustomTileStatePersister(impl: CustomTileStatePersisterImpl): CustomTileStatePersister
+
+ companion object {
+
+ @Provides fun provideTilesTheme(context: Context): Theme = context.theme
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 2350b5dce8b8..9d214e7141a8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -59,12 +59,12 @@ import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
import com.android.systemui.Prefs;
-import com.android.systemui.res.R;
import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.wifitrackerlib.WifiEntry;
@@ -157,14 +157,6 @@ public class InternetDialog extends SystemUIDialog implements
// Wi-Fi scanning progress bar
protected boolean mIsProgressBarVisible;
- protected boolean mIsSearchingHidden;
- protected final Runnable mHideProgressBarRunnable = () -> {
- setProgressBarVisible(false);
- };
- protected Runnable mHideSearchingRunnable = () -> {
- mIsSearchingHidden = true;
- mInternetDialogSubTitle.setText(getSubtitleText());
- };
@Inject
public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
@@ -285,8 +277,6 @@ public class InternetDialog extends SystemUIDialog implements
if (DEBUG) {
Log.d(TAG, "onStop");
}
- mHandler.removeCallbacks(mHideProgressBarRunnable);
- mHandler.removeCallbacks(mHideSearchingRunnable);
mMobileNetworkLayout.setOnClickListener(null);
mConnectedWifListLayout.setOnClickListener(null);
if (mSecondaryMobileNetworkLayout != null) {
@@ -335,7 +325,6 @@ public class InternetDialog extends SystemUIDialog implements
return;
}
- showProgressBar();
final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
final boolean isWifiEnabled = mInternetDialogController.isWifiEnabled();
final boolean isWifiScanEnabled = mInternetDialogController.isWifiScanEnabled();
@@ -641,8 +630,7 @@ public class InternetDialog extends SystemUIDialog implements
@Nullable
CharSequence getSubtitleText() {
- return mInternetDialogController.getSubtitleText(
- mIsProgressBarVisible && !mIsSearchingHidden);
+ return mInternetDialogController.getSubtitleText(mIsProgressBarVisible);
}
private Drawable getSignalStrengthDrawable(int subId) {
@@ -657,20 +645,6 @@ public class InternetDialog extends SystemUIDialog implements
return mInternetDialogController.getMobileNetworkSummary(subId);
}
- protected void showProgressBar() {
- if (!mInternetDialogController.isWifiEnabled()
- || mInternetDialogController.isDeviceLocked()) {
- setProgressBarVisible(false);
- return;
- }
- setProgressBarVisible(true);
- if (mConnectedWifiEntry != null || mWifiEntriesCount > 0) {
- mHandler.postDelayed(mHideProgressBarRunnable, PROGRESS_DELAY_MS);
- } else if (!mIsSearchingHidden) {
- mHandler.postDelayed(mHideSearchingRunnable, PROGRESS_DELAY_MS);
- }
- }
-
private void setProgressBarVisible(boolean visible) {
if (mIsProgressBarVisible == visible) {
return;
@@ -823,6 +797,11 @@ public class InternetDialog extends SystemUIDialog implements
}
@Override
+ public void onWifiScan(boolean isScan) {
+ setProgressBarVisible(isScan);
+ }
+
+ @Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (mAlertDialog != null && !mAlertDialog.isShowing()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index f516f5521d25..592cb3b18e80 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -75,7 +75,6 @@ import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.settingslib.wifi.WifiUtils;
import com.android.settingslib.wifi.dpp.WifiDppIntentHelper;
-import com.android.systemui.res.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -84,6 +83,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.LocationController;
@@ -1129,6 +1129,15 @@ public class InternetDialogController implements AccessPointController.AccessPoi
public void onSettingsActivityTriggered(Intent settingsIntent) {
}
+ @Override
+ public void onWifiScan(boolean isScan) {
+ if (!isWifiEnabled() || isDeviceLocked()) {
+ mCallback.onWifiScan(false);
+ return;
+ }
+ mCallback.onWifiScan(isScan);
+ }
+
private class InternetTelephonyCallback extends TelephonyCallback implements
TelephonyCallback.DataConnectionStateListener,
TelephonyCallback.DisplayInfoListener,
@@ -1372,6 +1381,8 @@ public class InternetDialogController implements AccessPointController.AccessPoi
void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
@Nullable WifiEntry connectedEntry, boolean hasMoreWifiEntries);
+
+ void onWifiScan(boolean isScan);
}
void makeOverlayToast(int stringId) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt
index cfb544226c83..9b8dba166274 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.airplane.domain
import android.content.res.Resources
+import android.content.res.Resources.Theme
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
@@ -27,18 +28,25 @@ import com.android.systemui.res.R
import javax.inject.Inject
/** Maps [AirplaneModeTileModel] to [QSTileState]. */
-class AirplaneModeMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<AirplaneModeTileModel> {
+class AirplaneModeMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ val theme: Theme,
+) : QSTileDataToStateMapper<AirplaneModeTileModel> {
override fun map(config: QSTileConfig, data: AirplaneModeTileModel): QSTileState =
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
val icon =
- Icon.Resource(
- if (data.isEnabled) {
- R.drawable.qs_airplane_icon_on
- } else {
- R.drawable.qs_airplane_icon_off
- },
+ Icon.Loaded(
+ resources.getDrawable(
+ if (data.isEnabled) {
+ R.drawable.qs_airplane_icon_on
+ } else {
+ R.drawable.qs_airplane_icon_off
+ },
+ theme,
+ ),
contentDescription = null
)
this.icon = { icon }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt
index 63865777e14f..e075e76595d4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.alarm.domain
import android.content.res.Resources
+import android.content.res.Resources.Theme
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel
@@ -30,14 +31,18 @@ import java.util.TimeZone
import javax.inject.Inject
/** Maps [AlarmTileModel] to [QSTileState]. */
-class AlarmTileMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<AlarmTileModel> {
+class AlarmTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Theme,
+) : QSTileDataToStateMapper<AlarmTileModel> {
companion object {
val formatter12Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("E hh:mm a")
val formatter24Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("E HH:mm")
}
override fun map(config: QSTileConfig, data: AlarmTileModel): QSTileState =
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
when (data) {
is AlarmTileModel.NextAlarmSet -> {
activationState = QSTileState.ActivationState.ACTIVE
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/flashlight/domain/FlashlightMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt
index 881a6bd156d2..1b3b5848a7ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.flashlight.domain
import android.content.res.Resources
+import android.content.res.Resources.Theme
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
@@ -27,18 +28,25 @@ import com.android.systemui.res.R
import javax.inject.Inject
/** Maps [FlashlightTileModel] to [QSTileState]. */
-class FlashlightMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<FlashlightTileModel> {
+class FlashlightMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Theme,
+) : QSTileDataToStateMapper<FlashlightTileModel> {
override fun map(config: QSTileConfig, data: FlashlightTileModel): QSTileState =
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
val icon =
- Icon.Resource(
- if (data.isEnabled) {
- R.drawable.qs_flashlight_icon_on
- } else {
- R.drawable.qs_flashlight_icon_off
- },
+ Icon.Loaded(
+ resources.getDrawable(
+ if (data.isEnabled) {
+ R.drawable.qs_flashlight_icon_on
+ } else {
+ R.drawable.qs_flashlight_icon_off
+ },
+ theme,
+ ),
contentDescription = null
)
this.icon = { icon }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt
index 7e7034d65efd..fe5445d00670 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.location.domain
import android.content.res.Resources
+import android.content.res.Resources.Theme
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
@@ -27,18 +28,25 @@ import com.android.systemui.res.R
import javax.inject.Inject
/** Maps [LocationTileModel] to [QSTileState]. */
-class LocationTileMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<LocationTileModel> {
+class LocationTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Theme,
+) : QSTileDataToStateMapper<LocationTileModel> {
override fun map(config: QSTileConfig, data: LocationTileModel): QSTileState =
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
val icon =
- Icon.Resource(
- if (data.isEnabled) {
- R.drawable.qs_location_icon_on
- } else {
- R.drawable.qs_location_icon_off
- },
+ Icon.Loaded(
+ resources.getDrawable(
+ if (data.isEnabled) {
+ R.drawable.qs_location_icon_on
+ } else {
+ R.drawable.qs_location_icon_off
+ },
+ theme,
+ ),
contentDescription = null
)
this.icon = { icon }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt
index 25b09131522b..df25600228a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt
@@ -27,20 +27,28 @@ import com.android.systemui.res.R
import javax.inject.Inject
/** Maps [DataSaverTileModel] to [QSTileState]. */
-class DataSaverTileMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<DataSaverTileModel> {
+class DataSaverTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Resources.Theme,
+) : QSTileDataToStateMapper<DataSaverTileModel> {
override fun map(config: QSTileConfig, data: DataSaverTileModel): QSTileState =
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
with(data) {
+ val iconRes: Int
if (isEnabled) {
activationState = QSTileState.ActivationState.ACTIVE
- icon = { Icon.Resource(R.drawable.qs_data_saver_icon_on, null) }
+ iconRes = R.drawable.qs_data_saver_icon_on
secondaryLabel = resources.getStringArray(R.array.tile_states_saver)[2]
} else {
activationState = QSTileState.ActivationState.INACTIVE
- icon = { Icon.Resource(R.drawable.qs_data_saver_icon_off, null) }
+ iconRes = R.drawable.qs_data_saver_icon_off
secondaryLabel = resources.getStringArray(R.array.tile_states_saver)[1]
}
+ val loadedIcon =
+ Icon.Loaded(resources.getDrawable(iconRes, theme), contentDescription = null)
+ icon = { loadedIcon }
contentDescription = label
supportedActions =
setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt
index 3f30c75a6b6a..ffef2b6ecfb5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt
@@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles.impl.uimodenight.domain
import android.app.UiModeManager
import android.content.res.Resources
+import android.content.res.Resources.Theme
import android.text.TextUtils
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.qualifiers.Main
@@ -31,15 +32,19 @@ import java.time.format.DateTimeFormatter
import javax.inject.Inject
/** Maps [UiModeNightTileModel] to [QSTileState]. */
-class UiModeNightTileMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<UiModeNightTileModel> {
+class UiModeNightTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Theme,
+) : QSTileDataToStateMapper<UiModeNightTileModel> {
companion object {
val formatter12Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("hh:mm a")
val formatter24Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm")
}
override fun map(config: QSTileConfig, data: UiModeNightTileModel): QSTileState =
with(data) {
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
var shouldSetSecondaryLabel = false
if (isPowerSave) {
@@ -116,8 +121,9 @@ class UiModeNightTileMapper @Inject constructor(@Main private val resources: Res
if (activationState == QSTileState.ActivationState.ACTIVE)
R.drawable.qs_light_dark_theme_icon_on
else R.drawable.qs_light_dark_theme_icon_off
- val iconResource = Icon.Resource(iconRes, null)
- icon = { iconResource }
+ val loadedIcon =
+ Icon.Loaded(resources.getDrawable(iconRes, theme), contentDescription = null)
+ icon = { loadedIcon }
supportedActions =
if (activationState == QSTileState.ActivationState.UNAVAILABLE)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
index 23e0cb66bb6a..be1b7404314f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.viewmodel
import android.content.res.Resources
+import android.content.res.Resources.Theme
import android.service.quicksettings.Tile
import android.view.View
import android.widget.Switch
@@ -47,14 +48,17 @@ data class QSTileState(
fun build(
resources: Resources,
+ theme: Theme,
config: QSTileUIConfig,
build: Builder.() -> Unit
- ): QSTileState =
- build(
- { Icon.Resource(config.iconRes, null) },
+ ): QSTileState {
+ val iconDrawable = resources.getDrawable(config.iconRes, theme)
+ return build(
+ { Icon.Loaded(iconDrawable, null) },
resources.getString(config.labelRes),
build,
)
+ }
fun build(icon: () -> Icon, label: CharSequence, build: Builder.() -> Unit): QSTileState =
Builder(icon, label).apply(build).build()
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..8221c635741b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recordissue
+
+import android.annotation.SuppressLint
+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.statusbar.phone.SystemUIDialog
+
+class RecordIssueDialogDelegate(
+ private val factory: SystemUIDialog.Factory,
+ 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()
+ 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()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
index 8a93ef65b4bf..d3459b109d79 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
@@ -32,6 +32,7 @@ import javax.inject.Inject
* TODO(b/200063118): Make this class the one source of truth for the state of panel expansion.
*/
@SysUISingleton
+@Deprecated("Use ShadeInteractor instead")
class ShadeExpansionStateManager @Inject constructor() {
private val expansionListeners = CopyOnWriteArrayList<ShadeExpansionListener>()
@@ -49,6 +50,7 @@ class ShadeExpansionStateManager @Inject constructor() {
*
* @see #addExpansionListener
*/
+ @Deprecated("Use ShadeInteractor instead")
fun addExpansionListener(listener: ShadeExpansionListener): ShadeExpansionChangeEvent {
expansionListeners.add(listener)
return ShadeExpansionChangeEvent(fraction, expanded, tracking, dragDownPxAmount)
@@ -60,6 +62,7 @@ class ShadeExpansionStateManager @Inject constructor() {
}
/** Adds a listener that will be notified when the panel state has changed. */
+ @Deprecated("Use ShadeInteractor instead")
fun addStateListener(listener: ShadeStateListener) {
stateListeners.add(listener)
}
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/connectivity/AccessPointController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt
index 490994d805fe..fc474d2a1307 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt
@@ -89,5 +89,12 @@ interface AccessPointController {
* "wifi_start_connect_ssid" set as an extra
*/
fun onSettingsActivityTriggered(settingsIntent: Intent?)
+
+ /**
+ * Called whenever a Wi-Fi scan is triggered.
+ *
+ * @param isScan Whether Wi-Fi scan is triggered or not.
+ */
+ fun onWifiScan(isScan: Boolean)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
index 91ca148c93c9..3a31851bcb4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
@@ -213,6 +213,12 @@ public class AccessPointControllerImpl implements AccessPointController,
}
}
+ private void fireWifiScanCallback(boolean isScan) {
+ for (AccessPointCallback callback : mCallbacks) {
+ callback.onWifiScan(isScan);
+ }
+ }
+
void dump(PrintWriter pw) {
IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
ipw.println("AccessPointControllerImpl:");
@@ -240,6 +246,14 @@ public class AccessPointControllerImpl implements AccessPointController,
}
@Override
+ public void onWifiEntriesChanged(@WifiPickerTracker.WifiEntriesChangedReason int reason) {
+ onWifiEntriesChanged();
+ if (reason == WifiPickerTracker.WIFI_ENTRIES_CHANGED_REASON_SCAN_RESULTS) {
+ fireWifiScanCallback(false /* isScan */);
+ }
+ }
+
+ @Override
public void onNumSavedNetworksChanged() {
// Do nothing
}
@@ -249,6 +263,11 @@ public class AccessPointControllerImpl implements AccessPointController,
// Do nothing
}
+ @Override
+ public void onScanRequested() {
+ fireWifiScanCallback(true /* isScan */);
+ }
+
private final WifiEntry.ConnectCallback mConnectCallback = new WifiEntry.ConnectCallback() {
@Override
public void onConnectResult(int status) {
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/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
index adf6cca1ac65..625fdc1c12f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
@@ -20,6 +20,8 @@ package com.android.systemui.statusbar.notification.stack.domain.interactor
import android.content.Context
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.SplitShadeStateController
import javax.inject.Inject
@@ -28,6 +30,7 @@ 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
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
@@ -39,7 +42,9 @@ class SharedNotificationContainerInteractor
constructor(
configurationRepository: ConfigurationRepository,
private val context: Context,
- private val splitShadeStateController: SplitShadeStateController
+ private val splitShadeStateController: SplitShadeStateController,
+ keyguardInteractor: KeyguardInteractor,
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
) {
private val _topPosition = MutableStateFlow(0f)
@@ -75,6 +80,19 @@ constructor(
}
.distinctUntilChanged()
+ /**
+ * The notification shelf can extend over the lock icon area if:
+ * * UDFPS supported. Ambient indication will always appear below
+ * * UDFPS not supported and ambient indication not visible, which will appear above lock icon
+ */
+ val useExtraShelfSpace: Flow<Boolean> =
+ combine(
+ keyguardInteractor.ambientIndicationVisible,
+ deviceEntryUdfpsInteractor.isUdfpsSupported,
+ ) { ambientIndicationVisible, isUdfpsSupported ->
+ isUdfpsSupported || !ambientIndicationVisible
+ }
+
val isSplitShadeEnabled: Flow<Boolean> =
configurationBasedDimensions
.map { dimens: ConfigurationBasedDimensions -> dimens.useSplitShade }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index af56a3f51281..12927b87630e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -101,12 +101,13 @@ object SharedNotificationContainerBinder {
launch {
viewModel
- .getMaxNotifications { space ->
+ .getMaxNotifications { space, extraShelfSpace ->
+ val shelfHeight = controller.getShelfHeight().toFloat()
notificationStackSizeCalculator.computeMaxKeyguardNotifications(
controller.getView(),
space,
- 0f, // Vertical space for shelf is already accounted for
- controller.getShelfHeight().toFloat(),
+ if (extraShelfSpace) shelfHeight else 0f,
+ shelfHeight,
)
}
.collect { controller.setMaxDisplayedNotifications(it) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 9594bc3bfd86..eff91e55d9a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -229,7 +229,7 @@ constructor(
* When expanding or when the user is interacting with the shade, keep the count stable; do not
* emit a value.
*/
- fun getMaxNotifications(calculateSpace: (Float) -> Int): Flow<Int> {
+ fun getMaxNotifications(calculateSpace: (Float, Boolean) -> Int): Flow<Int> {
val showLimitedNotifications = isOnLockscreenWithoutShade
val showUnlimitedNotifications =
combine(
@@ -245,11 +245,17 @@ constructor(
shadeInteractor.isUserInteracting,
bounds,
interactor.notificationStackChanged.onStart { emit(Unit) },
- ) { showLimitedNotifications, showUnlimitedNotifications, isUserInteracting, bounds, _
- ->
+ interactor.useExtraShelfSpace,
+ ) { flows ->
+ val showLimitedNotifications = flows[0] as Boolean
+ val showUnlimitedNotifications = flows[1] as Boolean
+ val isUserInteracting = flows[2] as Boolean
+ val bounds = flows[3] as NotificationContainerBounds
+ val useExtraShelfSpace = flows[5] as Boolean
+
if (!isUserInteracting) {
if (showLimitedNotifications) {
- emit(calculateSpace(bounds.bottom - bounds.top))
+ emit(calculateSpace(bounds.bottom - bounds.top, useExtraShelfSpace))
} else if (showUnlimitedNotifications) {
emit(-1)
}
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/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/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/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/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..4ef18cf1a15f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -93,6 +93,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 +191,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>
@@ -1131,7 +1133,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/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/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 687800714e05..459a74c82da4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -184,6 +184,13 @@ class KeyguardRootViewModelTest : SysuiTestCase() {
}
@Test
+ fun translationYInitialValueIsZero() =
+ testScope.runTest {
+ val translationY by collectLastValue(underTest.translationY)
+ assertThat(translationY).isEqualTo(0)
+ }
+
+ @Test
fun translationAndScaleFromBurnInNotDozing() =
testScope.runTest {
val translationX by collectLastValue(underTest.translationX)
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/privacy/PrivacyDialogControllerV2Test.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
index 0a8c0ab9817d..e4432f3038bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
@@ -31,18 +31,20 @@ import android.permission.PermissionGroupUsage
import android.permission.PermissionManager
import android.testing.AndroidTestingRunner
import android.view.View
+import android.widget.LinearLayout
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.animation.LaunchableView
import com.android.systemui.appops.AppOpsController
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.capture
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.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -56,12 +58,12 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -83,60 +85,48 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
private val TEST_INTENT = Intent("test_intent_action")
}
- @Mock
- private lateinit var dialog: PrivacyDialogV2
- @Mock
- private lateinit var permissionManager: PermissionManager
- @Mock
- private lateinit var packageManager: PackageManager
- @Mock
- private lateinit var privacyItemController: PrivacyItemController
- @Mock
- private lateinit var userTracker: UserTracker
- @Mock
- private lateinit var activityStarter: ActivityStarter
- @Mock
- private lateinit var privacyLogger: PrivacyLogger
- @Mock
- private lateinit var keyguardStateController: KeyguardStateController
- @Mock
- private lateinit var appOpsController: AppOpsController
+ @Mock private lateinit var dialog: PrivacyDialogV2
+ @Mock private lateinit var permissionManager: PermissionManager
+ @Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var privacyItemController: PrivacyItemController
+ @Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var privacyLogger: PrivacyLogger
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var appOpsController: AppOpsController
@Captor
private lateinit var dialogDismissedCaptor: ArgumentCaptor<PrivacyDialogV2.OnDialogDismissed>
- @Captor
- private lateinit var activityStartedCaptor: ArgumentCaptor<ActivityStarter.Callback>
- @Captor
- private lateinit var intentCaptor: ArgumentCaptor<Intent>
- @Mock
- private lateinit var uiEventLogger: UiEventLogger
- @Mock
- private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
+ @Captor private lateinit var activityStartedCaptor: ArgumentCaptor<ActivityStarter.Callback>
+ @Captor private lateinit var intentCaptor: ArgumentCaptor<Intent>
+ @Mock private lateinit var uiEventLogger: UiEventLogger
+ @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
private val backgroundExecutor = FakeExecutor(FakeSystemClock())
private val uiExecutor = FakeExecutor(FakeSystemClock())
private lateinit var controller: PrivacyDialogControllerV2
private var nextUid: Int = 0
- private val dialogProvider = object : PrivacyDialogControllerV2.DialogProvider {
- var list: List<PrivacyDialogV2.PrivacyElement>? = null
- var manageApp: ((String, Int, Intent) -> Unit)? = null
- var closeApp: ((String, Int) -> Unit)? = null
- var openPrivacyDashboard: (() -> Unit)? = null
-
- override fun makeDialog(
- context: Context,
- list: List<PrivacyDialogV2.PrivacyElement>,
- manageApp: (String, Int, Intent) -> Unit,
- closeApp: (String, Int) -> Unit,
- openPrivacyDashboard: () -> Unit
- ): PrivacyDialogV2 {
- this.list = list
- this.manageApp = manageApp
- this.closeApp = closeApp
- this.openPrivacyDashboard = openPrivacyDashboard
- return dialog
+ private val dialogProvider =
+ object : PrivacyDialogControllerV2.DialogProvider {
+ var list: List<PrivacyDialogV2.PrivacyElement>? = null
+ var manageApp: ((String, Int, Intent) -> Unit)? = null
+ var closeApp: ((String, Int) -> Unit)? = null
+ var openPrivacyDashboard: (() -> Unit)? = null
+
+ override fun makeDialog(
+ context: Context,
+ list: List<PrivacyDialogV2.PrivacyElement>,
+ manageApp: (String, Int, Intent) -> Unit,
+ closeApp: (String, Int) -> Unit,
+ openPrivacyDashboard: () -> Unit
+ ): PrivacyDialogV2 {
+ this.list = list
+ this.manageApp = manageApp
+ this.closeApp = closeApp
+ this.openPrivacyDashboard = openPrivacyDashboard
+ return dialog
+ }
}
- }
@Before
fun setUp() {
@@ -144,7 +134,8 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
nextUid = 0
setUpDefaultMockResponses()
- controller = PrivacyDialogControllerV2(
+ controller =
+ PrivacyDialogControllerV2(
permissionManager,
packageManager,
privacyItemController,
@@ -158,7 +149,7 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
uiEventLogger,
dialogLaunchAnimator,
dialogProvider
- )
+ )
}
@After
@@ -197,7 +188,7 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
verify(packageManager, never()).getApplicationInfoAsUser(anyString(), anyInt(), anyInt())
backgroundExecutor.runAllReady()
verify(packageManager, atLeastOnce())
- .getApplicationInfoAsUser(anyString(), anyInt(), anyInt())
+ .getApplicationInfoAsUser(anyString(), anyInt(), anyInt())
}
@Test
@@ -208,20 +199,25 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
controller.showDialog(context)
exhaustExecutors()
- verify(dialogLaunchAnimator, never()).showFromView(any(), any(), any(), anyBoolean())
+ verify(dialogLaunchAnimator, never()).show(any(), any(), anyBoolean())
verify(dialog).show()
}
@Test
fun testShowDialogShowsDialogWithView() {
- val view = View(context)
+ val parent = LinearLayout(context)
+ val view =
+ object : View(context), LaunchableView {
+ override fun setShouldBlockVisibilityChanges(block: Boolean) {}
+ }
+ parent.addView(view)
val usage = createMockPermGroupUsage()
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context, view)
exhaustExecutors()
- verify(dialogLaunchAnimator).showFromView(dialog, view)
+ verify(dialogLaunchAnimator).show(eq(dialog), any(), anyBoolean())
verify(dialog, never()).show()
}
@@ -276,7 +272,8 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testSingleElementInList() {
- val usage = createMockPermGroupUsage(
+ val usage =
+ createMockPermGroupUsage(
packageName = TEST_PACKAGE_NAME,
uid = generateUidForUser(USER_ID),
permissionGroupName = PERM_CAMERA,
@@ -285,7 +282,7 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
isPhoneCall = false,
attributionTag = null,
proxyLabel = TEST_PROXY_LABEL
- )
+ )
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
@@ -304,33 +301,38 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
assertThat(list.get(0).isPhoneCall).isFalse()
assertThat(list.get(0).isService).isFalse()
assertThat(list.get(0).permGroupName).isEqualTo(PERM_CAMERA)
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)
+ )
+ )
+ .isTrue()
}
}
private fun isIntentEqual(actual: Intent, expected: Intent): Boolean {
return actual.action == expected.action &&
- actual.getStringExtra(Intent.EXTRA_PACKAGE_NAME) ==
+ actual.getStringExtra(Intent.EXTRA_PACKAGE_NAME) ==
expected.getStringExtra(Intent.EXTRA_PACKAGE_NAME) &&
- actual.getParcelableExtra(Intent.EXTRA_USER) as? UserHandle ==
+ actual.getParcelableExtra(Intent.EXTRA_USER) as? UserHandle ==
expected.getParcelableExtra(Intent.EXTRA_USER) as? UserHandle
}
@Test
fun testTwoElementsDifferentType_sorted() {
- val usage_camera = createMockPermGroupUsage(
+ val usage_camera =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_camera",
permissionGroupName = PERM_CAMERA
- )
- val usage_microphone = createMockPermGroupUsage(
+ )
+ val usage_microphone =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_microphone",
permissionGroupName = PERM_MICROPHONE
- )
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_microphone, usage_camera)
- )
+ )
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_microphone, usage_camera))
controller.showDialog(context)
exhaustExecutors()
@@ -343,17 +345,12 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testTwoElementsSameType_oneActive() {
- val usage_active = createMockPermGroupUsage(
- packageName = "${TEST_PACKAGE_NAME}_active",
- isActive = true
- )
- val usage_recent = createMockPermGroupUsage(
- packageName = "${TEST_PACKAGE_NAME}_recent",
- isActive = false
- )
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_recent, usage_active)
- )
+ val usage_active =
+ createMockPermGroupUsage(packageName = "${TEST_PACKAGE_NAME}_active", isActive = true)
+ val usage_recent =
+ createMockPermGroupUsage(packageName = "${TEST_PACKAGE_NAME}_recent", isActive = false)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_recent, usage_active))
controller.showDialog(context)
exhaustExecutors()
@@ -364,19 +361,20 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testTwoElementsSameType_twoActive() {
- val usage_active = createMockPermGroupUsage(
+ val usage_active =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_active",
isActive = true,
lastAccessTimeMillis = 0L
- )
- val usage_active_moreRecent = createMockPermGroupUsage(
+ )
+ val usage_active_moreRecent =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_active_recent",
isActive = true,
lastAccessTimeMillis = 1L
- )
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_active, usage_active_moreRecent)
- )
+ )
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_active, usage_active_moreRecent))
controller.showDialog(context)
exhaustExecutors()
assertThat(dialogProvider.list).hasSize(2)
@@ -386,24 +384,26 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testManyElementsSameType_bothRecent() {
- val usage_recent = createMockPermGroupUsage(
+ val usage_recent =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_recent",
isActive = false,
lastAccessTimeMillis = 0L
- )
- val usage_moreRecent = createMockPermGroupUsage(
+ )
+ val usage_moreRecent =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_moreRecent",
isActive = false,
lastAccessTimeMillis = 1L
- )
- val usage_mostRecent = createMockPermGroupUsage(
+ )
+ val usage_mostRecent =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_mostRecent",
isActive = false,
lastAccessTimeMillis = 2L
- )
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_recent, usage_mostRecent, usage_moreRecent)
- )
+ )
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_recent, usage_mostRecent, usage_moreRecent))
controller.showDialog(context)
exhaustExecutors()
@@ -414,19 +414,12 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testMicAndCameraDisabled() {
- val usage_camera = createMockPermGroupUsage(
- permissionGroupName = PERM_CAMERA
- )
- val usage_microphone = createMockPermGroupUsage(
- permissionGroupName = PERM_MICROPHONE
- )
- val usage_location = createMockPermGroupUsage(
- permissionGroupName = PERM_LOCATION
- )
-
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_camera, usage_location, usage_microphone)
- )
+ val usage_camera = createMockPermGroupUsage(permissionGroupName = PERM_CAMERA)
+ val usage_microphone = createMockPermGroupUsage(permissionGroupName = PERM_MICROPHONE)
+ val usage_location = createMockPermGroupUsage(permissionGroupName = PERM_LOCATION)
+
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_camera, usage_location, usage_microphone))
`when`(privacyItemController.micCameraAvailable).thenReturn(false)
controller.showDialog(context)
@@ -438,45 +431,29 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testLocationDisabled() {
- val usage_camera = createMockPermGroupUsage(
- permissionGroupName = PERM_CAMERA
- )
- val usage_microphone = createMockPermGroupUsage(
- permissionGroupName = PERM_MICROPHONE
- )
- val usage_location = createMockPermGroupUsage(
- permissionGroupName = PERM_LOCATION
- )
-
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_camera, usage_location, usage_microphone)
- )
+ val usage_camera = createMockPermGroupUsage(permissionGroupName = PERM_CAMERA)
+ val usage_microphone = createMockPermGroupUsage(permissionGroupName = PERM_MICROPHONE)
+ val usage_location = createMockPermGroupUsage(permissionGroupName = PERM_LOCATION)
+
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_camera, usage_location, usage_microphone))
`when`(privacyItemController.locationAvailable).thenReturn(false)
controller.showDialog(context)
exhaustExecutors()
assertThat(dialogProvider.list).hasSize(2)
- dialogProvider.list?.forEach {
- assertThat(it.type).isNotEqualTo(PrivacyType.TYPE_LOCATION)
- }
+ dialogProvider.list?.forEach { assertThat(it.type).isNotEqualTo(PrivacyType.TYPE_LOCATION) }
}
@Test
fun testAllIndicatorsAvailable() {
- val usage_camera = createMockPermGroupUsage(
- permissionGroupName = PERM_CAMERA
- )
- val usage_microphone = createMockPermGroupUsage(
- permissionGroupName = PERM_MICROPHONE
- )
- val usage_location = createMockPermGroupUsage(
- permissionGroupName = PERM_LOCATION
- )
-
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_camera, usage_location, usage_microphone)
- )
+ val usage_camera = createMockPermGroupUsage(permissionGroupName = PERM_CAMERA)
+ val usage_microphone = createMockPermGroupUsage(permissionGroupName = PERM_MICROPHONE)
+ val usage_location = createMockPermGroupUsage(permissionGroupName = PERM_LOCATION)
+
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_camera, usage_location, usage_microphone))
`when`(privacyItemController.micCameraAvailable).thenReturn(true)
`when`(privacyItemController.locationAvailable).thenReturn(true)
@@ -488,19 +465,12 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testNoIndicatorsAvailable() {
- val usage_camera = createMockPermGroupUsage(
- permissionGroupName = PERM_CAMERA
- )
- val usage_microphone = createMockPermGroupUsage(
- permissionGroupName = PERM_MICROPHONE
- )
- val usage_location = createMockPermGroupUsage(
- permissionGroupName = PERM_LOCATION
- )
-
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_camera, usage_location, usage_microphone)
- )
+ val usage_camera = createMockPermGroupUsage(permissionGroupName = PERM_CAMERA)
+ val usage_microphone = createMockPermGroupUsage(permissionGroupName = PERM_MICROPHONE)
+ val usage_location = createMockPermGroupUsage(permissionGroupName = PERM_LOCATION)
+
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_camera, usage_location, usage_microphone))
`when`(privacyItemController.micCameraAvailable).thenReturn(false)
`when`(privacyItemController.locationAvailable).thenReturn(false)
@@ -512,11 +482,9 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testNotCurrentUser() {
- val usage_other = createMockPermGroupUsage(
- uid = generateUidForUser(ENT_USER_ID + 1)
- )
+ val usage_other = createMockPermGroupUsage(uid = generateUidForUser(ENT_USER_ID + 1))
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
- .thenReturn(listOf(usage_other))
+ .thenReturn(listOf(usage_other))
controller.showDialog(context)
exhaustExecutors()
@@ -559,9 +527,7 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
// Calls happen in
val usage = createMockPermGroupUsage(uid = SYSTEM_UID, isPhoneCall = true)
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
- `when`(userTracker.userProfiles).thenReturn(listOf(
- UserInfo(ENT_USER_ID, "", 0)
- ))
+ `when`(userTracker.userProfiles).thenReturn(listOf(UserInfo(ENT_USER_ID, "", 0)))
controller.showDialog(context)
exhaustExecutors()
@@ -577,8 +543,12 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
exhaustExecutors()
dialogProvider.manageApp?.invoke(TEST_PACKAGE_NAME, USER_ID, TEST_INTENT)
- verify(uiEventLogger).log(PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_APP_SETTINGS,
- USER_ID, TEST_PACKAGE_NAME)
+ verify(uiEventLogger)
+ .log(
+ PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_APP_SETTINGS,
+ USER_ID,
+ TEST_PACKAGE_NAME
+ )
}
@Test
@@ -589,8 +559,12 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
exhaustExecutors()
dialogProvider.closeApp?.invoke(TEST_PACKAGE_NAME, USER_ID)
- verify(uiEventLogger).log(PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_CLOSE_APP,
- USER_ID, TEST_PACKAGE_NAME)
+ verify(uiEventLogger)
+ .log(
+ PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_CLOSE_APP,
+ USER_ID,
+ TEST_PACKAGE_NAME
+ )
}
@Test
@@ -629,9 +603,13 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
exhaustExecutors()
dialogProvider.list?.let { list ->
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)
+ )
+ )
+ .isTrue()
assertThat(list.get(0).isService).isFalse()
}
}
@@ -648,45 +626,58 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
exhaustExecutors()
dialogProvider.list?.let { list ->
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(
- TEST_PACKAGE_NAME, ENT_USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(
+ TEST_PACKAGE_NAME,
+ ENT_USER_ID
+ )
+ )
+ )
+ .isTrue()
assertThat(list.get(0).isService).isFalse()
}
}
@Test
fun testDefaultIntentOnInvalidAttributionTag() {
- val usage = createMockPermGroupUsage(
+ val usage =
+ createMockPermGroupUsage(
attributionTag = "INVALID_ATTRIBUTION_TAG",
proxyLabel = TEST_PROXY_LABEL
- )
+ )
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
exhaustExecutors()
dialogProvider.list?.let { list ->
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)
+ )
+ )
+ .isTrue()
assertThat(list.get(0).isService).isFalse()
}
}
@Test
fun testServiceIntentOnCorrectSubAttribution() {
- val usage = createMockPermGroupUsage(
+ val usage =
+ createMockPermGroupUsage(
attributionTag = TEST_ATTRIBUTION_TAG,
attributionLabel = "TEST_LABEL"
- )
+ )
val activityInfo = createMockActivityInfo()
val resolveInfo = createMockResolveInfo(activityInfo)
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
- `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
- .thenAnswer { resolveInfo }
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())).thenAnswer {
+ resolveInfo
+ }
controller.showDialog(context)
exhaustExecutors()
@@ -694,57 +685,61 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
val navigationIntent = list.get(0).navigationIntent!!
assertThat(navigationIntent.action).isEqualTo(Intent.ACTION_MANAGE_PERMISSION_USAGE)
assertThat(navigationIntent.getStringExtra(Intent.EXTRA_PERMISSION_GROUP_NAME))
- .isEqualTo(PERM_CAMERA)
+ .isEqualTo(PERM_CAMERA)
assertThat(navigationIntent.getStringArrayExtra(Intent.EXTRA_ATTRIBUTION_TAGS))
- .isEqualTo(arrayOf(TEST_ATTRIBUTION_TAG.toString()))
+ .isEqualTo(arrayOf(TEST_ATTRIBUTION_TAG.toString()))
assertThat(navigationIntent.getBooleanExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, false))
- .isTrue()
+ .isTrue()
assertThat(list.get(0).isService).isTrue()
}
}
@Test
fun testDefaultIntentOnMissingAttributionLabel() {
- val usage = createMockPermGroupUsage(
- attributionTag = TEST_ATTRIBUTION_TAG
- )
+ val usage = createMockPermGroupUsage(attributionTag = TEST_ATTRIBUTION_TAG)
val activityInfo = createMockActivityInfo()
val resolveInfo = createMockResolveInfo(activityInfo)
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
- `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
- .thenAnswer { resolveInfo }
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())).thenAnswer {
+ resolveInfo
+ }
controller.showDialog(context)
exhaustExecutors()
dialogProvider.list?.let { list ->
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)
+ )
+ )
+ .isTrue()
assertThat(list.get(0).isService).isFalse()
}
}
@Test
fun testDefaultIntentOnIncorrectPermission() {
- val usage = createMockPermGroupUsage(
- attributionTag = TEST_ATTRIBUTION_TAG
- )
+ val usage = createMockPermGroupUsage(attributionTag = TEST_ATTRIBUTION_TAG)
- val activityInfo = createMockActivityInfo(
- permission = "INCORRECT_PERMISSION"
- )
+ val activityInfo = createMockActivityInfo(permission = "INCORRECT_PERMISSION")
val resolveInfo = createMockResolveInfo(activityInfo)
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
- `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
- .thenAnswer { resolveInfo }
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())).thenAnswer {
+ resolveInfo
+ }
controller.showDialog(context)
exhaustExecutors()
dialogProvider.list?.let { list ->
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)
+ )
+ )
+ .isTrue()
assertThat(list.get(0).isService).isFalse()
}
}
@@ -758,15 +753,18 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
`when`(appOpsController.isMicMuted).thenReturn(false)
`when`(packageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
- .thenAnswer { FakeApplicationInfo(it.getArgument(0)) }
+ .thenAnswer { FakeApplicationInfo(it.getArgument(0)) }
`when`(privacyItemController.locationAvailable).thenReturn(true)
`when`(privacyItemController.micCameraAvailable).thenReturn(true)
- `when`(userTracker.userProfiles).thenReturn(listOf(
- UserInfo(USER_ID, "", 0),
- UserInfo(ENT_USER_ID, "", UserInfo.FLAG_MANAGED_PROFILE)
- ))
+ `when`(userTracker.userProfiles)
+ .thenReturn(
+ listOf(
+ UserInfo(USER_ID, "", 0),
+ UserInfo(ENT_USER_ID, "", UserInfo.FLAG_MANAGED_PROFILE)
+ )
+ )
`when`(keyguardStateController.isUnlocked).thenReturn(true)
}
@@ -781,9 +779,7 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
return user * UserHandle.PER_USER_RANGE + nextUid++
}
- private fun createMockResolveInfo(
- activityInfo: ActivityInfo? = null
- ): ResolveInfo {
+ private fun createMockResolveInfo(activityInfo: ActivityInfo? = null): ResolveInfo {
val resolveInfo = mock(ResolveInfo::class.java)
resolveInfo.activityInfo = activityInfo
return resolveInfo
@@ -822,4 +818,4 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
`when`(usage.proxyLabel).thenReturn(proxyLabel)
return usage
}
-} \ No newline at end of file
+}
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..e9714dc524ee 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,19 @@ 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.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 +61,22 @@ 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
+ 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 +87,11 @@ class RecordIssueTileTest : SysuiTestCase() {
metricsLogger,
statusBarStateController,
activityStarter,
- qsLogger
+ qsLogger,
+ keyguardDismissUtil,
+ keyguardStateController,
+ dialogLauncherAnimator,
+ dialogFactory
)
}
@@ -119,4 +138,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/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 6dc7a064af15..b24b8773d600 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -63,13 +63,13 @@ import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.wifi.WifiUtils;
import com.android.settingslib.wifi.dpp.WifiDppIntentHelper;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.LocationController;
@@ -738,6 +738,44 @@ public class InternetDialogControllerTest extends SysuiTestCase {
}
@Test
+ public void onWifiScan_isWifiEnabledFalse_callbackOnWifiScanFalse() {
+ reset(mInternetDialogCallback);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(false);
+
+ mInternetDialogController.onWifiScan(true);
+
+ verify(mInternetDialogCallback).onWifiScan(false);
+ }
+
+ @Test
+ public void onWifiScan_isDeviceLockedTrue_callbackOnWifiScanFalse() {
+ reset(mInternetDialogCallback);
+ when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+
+ mInternetDialogController.onWifiScan(true);
+
+ verify(mInternetDialogCallback).onWifiScan(false);
+ }
+
+ @Test
+ public void onWifiScan_onWifiScanFalse_callbackOnWifiScanFalse() {
+ reset(mInternetDialogCallback);
+
+ mInternetDialogController.onWifiScan(false);
+
+ verify(mInternetDialogCallback).onWifiScan(false);
+ }
+
+ @Test
+ public void onWifiScan_onWifiScanTrue_callbackOnWifiScanTrue() {
+ reset(mInternetDialogCallback);
+
+ mInternetDialogController.onWifiScan(true);
+
+ verify(mInternetDialogCallback).onWifiScan(true);
+ }
+
+ @Test
public void setMergedCarrierWifiEnabledIfNeed_carrierProvisionsEnabled_doNothing() {
when(mCarrierConfigTracker.getCarrierProvisionsWifiMergedNetworksBool(SUB_ID))
.thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index 039e58a64eb5..916bb79d97b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -6,12 +6,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -33,9 +31,9 @@ import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -48,7 +46,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
@@ -613,66 +610,21 @@ public class InternetDialogTest extends SysuiTestCase {
}
@Test
- public void showProgressBar_wifiDisabled_hideProgressBar() {
- Mockito.reset(mHandler);
- when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
-
- mInternetDialog.showProgressBar();
-
- assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
- verify(mHandler, never()).postDelayed(any(Runnable.class), anyLong());
- }
-
- @Test
- public void showProgressBar_deviceLocked_hideProgressBar() {
- Mockito.reset(mHandler);
- when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
-
- mInternetDialog.showProgressBar();
-
- assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
- verify(mHandler, never()).postDelayed(any(Runnable.class), anyLong());
- }
-
- @Test
- public void showProgressBar_wifiEnabledWithWifiEntry_showProgressBarThenHide() {
- Mockito.reset(mHandler);
- when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
+ public void onWifiScan_isScanTrue_setProgressBarVisibleTrue() {
+ mInternetDialog.mIsProgressBarVisible = false;
- mInternetDialog.showProgressBar();
+ mInternetDialog.onWifiScan(true);
- // Show progress bar
assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
-
- ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mHandler).postDelayed(runnableCaptor.capture(),
- eq(InternetDialog.PROGRESS_DELAY_MS));
- runnableCaptor.getValue().run();
-
- // Then hide progress bar
- assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
}
@Test
- public void showProgressBar_wifiEnabledWithoutWifiEntries_showProgressBarThenHideSearch() {
- Mockito.reset(mHandler);
- when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
- mInternetDialog.mConnectedWifiEntry = null;
- mInternetDialog.mWifiEntriesCount = 0;
+ public void onWifiScan_isScanFalse_setProgressBarVisibleFalse() {
+ mInternetDialog.mIsProgressBarVisible = true;
- mInternetDialog.showProgressBar();
-
- // Show progress bar
- assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
+ mInternetDialog.onWifiScan(false);
- ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mHandler).postDelayed(runnableCaptor.capture(),
- eq(InternetDialog.PROGRESS_DELAY_MS));
- runnableCaptor.getValue().run();
-
- // Then hide searching sub-title only
- assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
- assertThat(mInternetDialog.mIsSearchingHidden).isTrue();
+ assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
}
@Test
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..bbc59d03ac2b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
@@ -0,0 +1,93 @@
+/*
+ * 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) { 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/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 657f9127dc7e..e572dcca5a34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -23,6 +23,8 @@ import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -37,8 +39,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-
import android.annotation.IdRes;
import android.content.ContentResolver;
import android.content.res.Configuration;
@@ -86,6 +86,7 @@ import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.view.LongPressHandlingView;
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
@@ -402,6 +403,10 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
mPowerInteractor = keyguardInteractorDeps.getPowerInteractor();
when(mKeyguardTransitionInteractor.isInTransitionToStateWhere(any())).thenReturn(
StateFlowKt.MutableStateFlow(false));
+ DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
+ mock(DeviceEntryUdfpsInteractor.class);
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
new FakeDeviceProvisioningRepository(),
@@ -418,7 +423,9 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
new SharedNotificationContainerInteractor(
new FakeConfigurationRepository(),
mContext,
- new ResourcesSplitShadeStateController()
+ new ResourcesSplitShadeStateController(),
+ mKeyguardInteractor,
+ deviceEntryUdfpsInteractor
),
mShadeRepository
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 5ffbe65d2c50..9d8b21464585 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -23,6 +23,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -54,6 +56,7 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -235,6 +238,11 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
mKeyguardSecurityModel,
mSelectedUserInteractor,
powerInteractor);
+
+ DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
+ mock(DeviceEntryUdfpsInteractor.class);
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
new FakeDeviceProvisioningRepository(),
@@ -251,7 +259,9 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
new SharedNotificationContainerInteractor(
configurationRepository,
mContext,
- new ResourcesSplitShadeStateController()),
+ new ResourcesSplitShadeStateController(),
+ keyguardInteractor,
+ deviceEntryUdfpsInteractor),
shadeRepository
)
);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index e723d7d0367b..eb5633b70f61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
import android.content.res.Resources;
@@ -41,6 +42,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
import com.android.systemui.flags.FeatureFlags;
@@ -275,6 +277,10 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
ResourcesSplitShadeStateController splitShadeStateController =
new ResourcesSplitShadeStateController();
+ DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
+ mock(DeviceEntryUdfpsInteractor.class);
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
deviceProvisioningRepository,
@@ -291,7 +297,9 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
new SharedNotificationContainerInteractor(
configurationRepository,
mContext,
- splitShadeStateController),
+ splitShadeStateController,
+ keyguardInteractor,
+ deviceEntryUdfpsInteractor),
mShadeRepository
)
);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index dff91ddf559f..f25ce0aa5278 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -27,6 +27,7 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -53,6 +54,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSe
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
import com.android.systemui.util.mockito.mock
+import kotlinx.coroutines.flow.emptyFlow
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -83,6 +85,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
FromPrimaryBouncerTransitionInteractor
@Mock lateinit var interactionJankMonitor: InteractionJankMonitor
@Mock lateinit var mockDarkAnimator: ObjectAnimator
+ @Mock lateinit var deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor
private lateinit var controller: StatusBarStateControllerImpl
private lateinit var uiEventLogger: UiEventLoggerFake
@@ -164,6 +167,8 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
mock(),
powerInteractor
)
+
+ whenever(deviceEntryUdfpsInteractor.isUdfpsSupported).thenReturn(emptyFlow())
shadeInteractor =
ShadeInteractorImpl(
testScope.backgroundScope,
@@ -181,7 +186,9 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
SharedNotificationContainerInteractor(
configurationRepository,
mContext,
- ResourcesSplitShadeStateController()
+ ResourcesSplitShadeStateController(),
+ keyguardInteractor,
+ deviceEntryUdfpsInteractor,
),
shadeRepository,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
index 3fef1d9832f0..5bc75e8b84c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
@@ -148,6 +148,24 @@ class AccessPointControllerImplTest : SysuiTestCase() {
}
@Test
+ fun onWifiEntriesChanged_reasonIsScanResults_fireWifiScanCallbackFalse() {
+ controller.addAccessPointCallback(callback)
+
+ controller.onWifiEntriesChanged(WifiPickerTracker.WIFI_ENTRIES_CHANGED_REASON_SCAN_RESULTS)
+
+ verify(callback).onWifiScan(false)
+ }
+
+ @Test
+ fun onScanRequested_fireWifiScanCallbackTrue() {
+ controller.addAccessPointCallback(callback)
+
+ controller.onScanRequested()
+
+ verify(callback).onWifiScan(true)
+ }
+
+ @Test
fun testOnNumSavedNetworksChangedDoesntTriggerCallback() {
controller.addAccessPointCallback(callback)
controller.onNumSavedNetworksChanged()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index bfa03eed57a0..8cf64a5aa8fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -48,7 +48,6 @@ import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
-import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -56,6 +55,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.log.LogAssertKt;
import com.android.systemui.statusbar.NotificationInteractionTracker;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
@@ -76,6 +76,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.util.time.FakeSystemClock;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -129,10 +130,6 @@ public class ShadeListBuilderTest extends SysuiTestCase {
private Map<String, Integer> mNextIdMap = new ArrayMap<>();
private int mNextRank = 0;
- private Log.TerribleFailureHandler mOldWtfHandler = null;
- private Log.TerribleFailure mLastWtf = null;
- private int mWtfCount = 0;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -1756,20 +1753,19 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addPreGroupFilter(filter);
mListBuilder.addOnBeforeTransformGroupsListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the filter is invalidated exactly
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
addNotif(0, PACKAGE_2);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
// THEN an exception is NOT thrown directly, but a WTF IS logged.
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+ LogAssertKt.assertLogsWtfs(() -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void testOutOfOrderPreGroupFilterInvalidationThrowsAfterTooManyRuns() {
// GIVEN a PreGroupNotifFilter that gets invalidated during the grouping stage,
NotifFilter filter = new PackageFilter(PACKAGE_1);
@@ -1778,20 +1774,20 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addPreGroupFilter(filter);
mListBuilder.addOnBeforeTransformGroupsListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the filter is invalidated more than
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
+
+ // THEN an exception IS thrown.
+
addNotif(0, PACKAGE_2);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
- dispatchBuild();
- try {
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- } finally {
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- }
- // THEN an exception IS thrown.
+ LogAssertKt.assertLogsWtfs(() -> {
+ Assert.assertThrows(IllegalStateException.class, () -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
+ });
}
@Test
@@ -1803,26 +1799,30 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addPreGroupFilter(filter);
mListBuilder.addOnBeforeTransformGroupsListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the filter is invalidated
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times, the pipeline runs for a non-reentrant reason,
// and then the filter is invalidated MAX_CONSECUTIVE_REENTRANT_REBUILDS times again,
+
+ // THEN an exception is NOT thrown, but WTFs ARE logged.
+
addNotif(0, PACKAGE_2);
+
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- // Note: dispatchBuild itself triggers a non-reentrant pipeline run.
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ LogAssertKt.assertLogsWtfs(() -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
- // THEN an exception is NOT thrown, but WTFs ARE logged.
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS * 2);
+ invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+ LogAssertKt.assertLogsWtfs(() -> {
+ // Note: dispatchBuild itself triggers a non-reentrant pipeline run.
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
}
@Test
- public void testOutOfOrderPrompterInvalidationDoesNotThrowBeforeTooManyRuns() {
+ public void testOutOfOrderPromoterInvalidationDoesNotThrowBeforeTooManyRuns() {
// GIVEN a NotifPromoter that gets invalidated during the sorting stage,
NotifPromoter promoter = new IdPromoter(47);
CountingInvalidator invalidator = new CountingInvalidator(promoter);
@@ -1830,22 +1830,22 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addPromoter(promoter);
mListBuilder.addOnBeforeSortListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the promoter is invalidated exactly
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
- addNotif(0, PACKAGE_1);
- invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
// THEN an exception is NOT thrown directly, but a WTF IS logged.
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+ addNotif(0, PACKAGE_1);
+ invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+
+ LogAssertKt.assertLogsWtfs(() -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
}
- @Test(expected = IllegalStateException.class)
- public void testOutOfOrderPrompterInvalidationThrowsAfterTooManyRuns() {
+ @Test
+ public void testOutOfOrderPromoterInvalidationThrowsAfterTooManyRuns() {
// GIVEN a NotifPromoter that gets invalidated during the sorting stage,
NotifPromoter promoter = new IdPromoter(47);
CountingInvalidator invalidator = new CountingInvalidator(promoter);
@@ -1853,20 +1853,20 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addPromoter(promoter);
mListBuilder.addOnBeforeSortListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the promoter is invalidated more than
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
+
+ // THEN an exception IS thrown.
+
addNotif(0, PACKAGE_1);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
- dispatchBuild();
- try {
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- } finally {
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- }
- // THEN an exception IS thrown.
+ LogAssertKt.assertLogsWtfs(() -> {
+ Assert.assertThrows(IllegalStateException.class, () -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
+ });
}
@Test
@@ -1878,20 +1878,21 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.setComparators(singletonList(comparator));
mListBuilder.addOnBeforeRenderListListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the comparator is invalidated exactly
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
+
+ // THEN an exception is NOT thrown directly, but a WTF IS logged.
+
addNotif(0, PACKAGE_2);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- // THEN an exception is NOT thrown directly, but a WTF IS logged.
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+ LogAssertKt.assertLogsWtfs(() -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void testOutOfOrderComparatorInvalidationThrowsAfterTooManyRuns() {
// GIVEN a NotifComparator that gets invalidated during the finalizing stage,
NotifComparator comparator = new HypeComparator(PACKAGE_1);
@@ -1900,16 +1901,20 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.setComparators(singletonList(comparator));
mListBuilder.addOnBeforeRenderListListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the comparator is invalidated more than
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
+
+ // THEN an exception IS thrown.
+
addNotif(0, PACKAGE_2);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- // THEN an exception IS thrown.
+ LogAssertKt.assertLogsWtfs(() -> {
+ Assert.assertThrows(IllegalStateException.class, () -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
+ });
}
@Test
@@ -1921,20 +1926,21 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addFinalizeFilter(filter);
mListBuilder.addOnBeforeRenderListListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the PreRenderFilter is invalidated exactly
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
+
+ // THEN an exception is NOT thrown directly, but a WTF IS logged.
+
addNotif(0, PACKAGE_2);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- // THEN an exception is NOT thrown directly, but a WTF IS logged.
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+ LogAssertKt.assertLogsWtfs(() -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void testOutOfOrderPreRenderFilterInvalidationThrowsAfterTooManyRuns() {
// GIVEN a PreRenderNotifFilter that gets invalidated during the finalizing stage,
NotifFilter filter = new PackageFilter(PACKAGE_1);
@@ -1943,59 +1949,22 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addFinalizeFilter(filter);
mListBuilder.addOnBeforeRenderListListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the PreRenderFilter is invalidated more than
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
- addNotif(0, PACKAGE_2);
- invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
- dispatchBuild();
- try {
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- } finally {
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- }
// THEN an exception IS thrown.
- }
-
- private void interceptWtfs() {
- assertNull(mOldWtfHandler);
- mLastWtf = null;
- mWtfCount = 0;
+ addNotif(0, PACKAGE_2);
+ invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
- mOldWtfHandler = Log.setWtfHandler((tag, e, system) -> {
- Log.e("ShadeListBuilderTest", "Observed WTF: " + e);
- mLastWtf = e;
- mWtfCount++;
+ LogAssertKt.assertLogsWtfs(() -> {
+ Assert.assertThrows(IllegalStateException.class, () -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
});
}
- private void expectNoWtfs() {
- assertNull(expectWtfs(0));
- }
-
- private Log.TerribleFailure expectWtf() {
- return expectWtfs(1);
- }
-
- private Log.TerribleFailure expectWtfs(int expectedWtfCount) {
- assertNotNull(mOldWtfHandler);
-
- Log.setWtfHandler(mOldWtfHandler);
- mOldWtfHandler = null;
-
- Log.TerribleFailure wtf = mLastWtf;
- int wtfCount = mWtfCount;
-
- mLastWtf = null;
- mWtfCount = 0;
-
- assertEquals(expectedWtfCount, wtfCount);
- return wtf;
- }
-
@Test
public void testStableOrdering() {
mStabilityManager.setAllowEntryReordering(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
index a07b5705d171..327a07d6179f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
@@ -20,57 +20,86 @@ package com.android.systemui.statusbar.notification.stack.domain.interactor
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
+import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class SharedNotificationContainerInteractorTest : SysuiTestCase() {
- private lateinit var configurationRepository: FakeConfigurationRepository
- private lateinit var underTest: SharedNotificationContainerInteractor
-
- @Before
- fun setUp() {
- configurationRepository = FakeConfigurationRepository()
- underTest =
- SharedNotificationContainerInteractor(
- configurationRepository,
- mContext,
- ResourcesSplitShadeStateController()
- )
- }
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val keyguardRepository = kosmos.fakeKeyguardRepository
+ private val configurationRepository = kosmos.fakeConfigurationRepository
+ private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+ private val underTest = kosmos.sharedNotificationContainerInteractor
@Test
- fun validateConfigValues() = runTest {
- overrideResource(R.bool.config_use_split_notification_shade, true)
- overrideResource(R.bool.config_use_large_screen_shade_header, false)
- overrideResource(R.dimen.notification_panel_margin_horizontal, 0)
- overrideResource(R.dimen.notification_panel_margin_bottom, 10)
- overrideResource(R.dimen.notification_panel_margin_top, 10)
- overrideResource(R.dimen.large_screen_shade_header_height, 0)
- overrideResource(R.dimen.keyguard_split_shade_top_margin, 55)
-
- val dimens = collectLastValue(underTest.configurationBasedDimensions)
-
- configurationRepository.onAnyConfigurationChange()
- runCurrent()
-
- val lastDimens = dimens()!!
-
- assertThat(lastDimens.useSplitShade).isTrue()
- assertThat(lastDimens.useLargeScreenHeader).isFalse()
- assertThat(lastDimens.marginHorizontal).isEqualTo(0)
- assertThat(lastDimens.marginBottom).isGreaterThan(0)
- assertThat(lastDimens.marginTop).isGreaterThan(0)
- assertThat(lastDimens.marginTopLargeScreen).isEqualTo(0)
- assertThat(lastDimens.keyguardSplitShadeTopMargin).isEqualTo(55)
- }
+ fun validateConfigValues() =
+ testScope.runTest {
+ overrideResource(R.bool.config_use_split_notification_shade, true)
+ overrideResource(R.bool.config_use_large_screen_shade_header, false)
+ overrideResource(R.dimen.notification_panel_margin_horizontal, 0)
+ overrideResource(R.dimen.notification_panel_margin_bottom, 10)
+ overrideResource(R.dimen.notification_panel_margin_top, 10)
+ overrideResource(R.dimen.large_screen_shade_header_height, 0)
+ overrideResource(R.dimen.keyguard_split_shade_top_margin, 55)
+
+ val dimens = collectLastValue(underTest.configurationBasedDimensions)
+
+ configurationRepository.onAnyConfigurationChange()
+ runCurrent()
+
+ val lastDimens = dimens()!!
+
+ assertThat(lastDimens.useSplitShade).isTrue()
+ assertThat(lastDimens.useLargeScreenHeader).isFalse()
+ assertThat(lastDimens.marginHorizontal).isEqualTo(0)
+ assertThat(lastDimens.marginBottom).isGreaterThan(0)
+ assertThat(lastDimens.marginTop).isGreaterThan(0)
+ assertThat(lastDimens.marginTopLargeScreen).isEqualTo(0)
+ assertThat(lastDimens.keyguardSplitShadeTopMargin).isEqualTo(55)
+ }
+
+ @Test
+ fun useExtraShelfSpaceIsTrueWithUdfps() =
+ testScope.runTest {
+ val useExtraShelfSpace by collectLastValue(underTest.useExtraShelfSpace)
+
+ keyguardRepository.ambientIndicationVisible.value = true
+ fingerprintPropertyRepository.supportsUdfps()
+
+ assertThat(useExtraShelfSpace).isEqualTo(true)
+ }
+
+ @Test
+ fun useExtraShelfSpaceIsTrueWithRearFpsAndNoAmbientIndicationArea() =
+ testScope.runTest {
+ val useExtraShelfSpace by collectLastValue(underTest.useExtraShelfSpace)
+
+ keyguardRepository.ambientIndicationVisible.value = false
+ fingerprintPropertyRepository.supportsRearFps()
+
+ assertThat(useExtraShelfSpace).isEqualTo(true)
+ }
+
+ @Test
+ fun useExtraShelfSpaceIsFalseWithRearFpsAndAmbientIndicationArea() =
+ testScope.runTest {
+ val useExtraShelfSpace by collectLastValue(underTest.useExtraShelfSpace)
+
+ keyguardRepository.ambientIndicationVisible.value = true
+ fingerprintPropertyRepository.supportsRearFps()
+
+ assertThat(useExtraShelfSpace).isEqualTo(false)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index f0205b3f5974..36a471238c8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -332,8 +332,8 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
fun maxNotificationsOnLockscreen() =
testScope.runTest {
var notificationCount = 10
- val maxNotifications by
- collectLastValue(underTest.getMaxNotifications { notificationCount })
+ val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> notificationCount }
+ val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
showLockscreen()
@@ -355,8 +355,8 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
fun maxNotificationsOnLockscreen_DoesNotUpdateWhenUserInteracting() =
testScope.runTest {
var notificationCount = 10
- val maxNotifications by
- collectLastValue(underTest.getMaxNotifications { notificationCount })
+ val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> notificationCount }
+ val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
showLockscreen()
@@ -390,7 +390,8 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
@Test
fun maxNotificationsOnShade() =
testScope.runTest {
- val maxNotifications by collectLastValue(underTest.getMaxNotifications { 10 })
+ val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> 10 }
+ val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
// Show lockscreen with shade expanded
showLockscreenWithShadeExpanded()
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/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 5b9b390eea2d..b217195000b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -29,6 +29,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -97,6 +99,7 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
@@ -465,6 +468,10 @@ public class BubblesTest extends SysuiTestCase {
ResourcesSplitShadeStateController splitShadeStateController =
new ResourcesSplitShadeStateController();
+ DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
+ mock(DeviceEntryUdfpsInteractor.class);
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+
mShadeInteractor =
new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
@@ -481,7 +488,9 @@ public class BubblesTest extends SysuiTestCase {
new SharedNotificationContainerInteractor(
configurationRepository,
mContext,
- splitShadeStateController),
+ splitShadeStateController,
+ keyguardInteractor,
+ deviceEntryUdfpsInteractor),
shadeRepository
)
);
diff --git a/packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt b/packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt
new file mode 100644
index 000000000000..b88f302cdfdd
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.graphics.drawable
+
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.PixelFormat
+
+/**
+ * Stub drawable that does nothing. It's to be used in tests as a mock drawable and checked for the
+ * same instance
+ */
+class TestStubDrawable : Drawable() {
+
+ override fun draw(canvas: Canvas) = Unit
+ override fun setAlpha(alpha: Int) = Unit
+ override fun setColorFilter(colorFilter: ColorFilter?) = Unit
+ override fun getOpacity(): Int = PixelFormat.UNKNOWN
+
+ override fun equals(other: Any?): Boolean = this === other
+}
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/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 0e7c6625264c..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
@@ -121,6 +125,8 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository {
override val lastRootViewTapPosition: MutableStateFlow<Point?> = MutableStateFlow(null)
+ override val ambientIndicationVisible: MutableStateFlow<Boolean> = MutableStateFlow(false)
+
override fun setQuickSettingsVisible(isVisible: Boolean) {
_isQuickSettingsVisible.value = isVisible
}
@@ -174,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/log/LogAssert.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
index 10f9346aba14..6ccb3bc2812e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
@@ -59,6 +59,17 @@ fun assertLogsWtf(
): TerribleFailureLog =
assertLogsWtf(message = message, allowMultiple = allowMultiple) { loggingRunnable.run() }
+fun assertLogsWtfs(
+ message: String = "Expected Log.wtf to be called once or more",
+ loggingBlock: () -> Unit,
+): TerribleFailureLog = assertLogsWtf(message, allowMultiple = true, loggingBlock)
+
+@JvmOverloads
+fun assertLogsWtfs(
+ message: String = "Expected Log.wtf to be called once or more",
+ loggingRunnable: Runnable,
+): TerribleFailureLog = assertLogsWtfs(message) { loggingRunnable.run() }
+
/** The data passed to [TerribleFailureHandler.onTerribleFailure] */
data class TerribleFailureLog(
val tag: String,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
index 1cb2587e4e99..6332c1a8010d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
@@ -19,9 +19,14 @@ package com.android.systemui.qs
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.plugins.qs.QSFactory
+import com.android.systemui.qs.tiles.di.NewQSTileFactory
val Kosmos.instanceIdSequenceFake: InstanceIdSequenceFake by
Kosmos.Fixture { InstanceIdSequenceFake(0) }
val Kosmos.uiEventLogger: UiEventLoggerFake by Kosmos.Fixture { UiEventLoggerFake() }
val Kosmos.qsEventLogger: QsEventLoggerFake by
Kosmos.Fixture { QsEventLoggerFake(uiEventLogger, instanceIdSequenceFake) }
+
+var Kosmos.newQSTileFactory by Kosmos.Fixture<NewQSTileFactory>()
+var Kosmos.qsTileFactory by Kosmos.Fixture<QSFactory>()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/CustomTileStatePersisterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/CustomTileStatePersisterKosmos.kt
new file mode 100644
index 000000000000..f01e3aaa7089
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/CustomTileStatePersisterKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.external
+
+import com.android.systemui.kosmos.Kosmos
+
+var Kosmos.customTileStatePersister: CustomTileStatePersister by
+ Kosmos.Fixture { fakeCustomTileStatePersister }
+val Kosmos.fakeCustomTileStatePersister by Kosmos.Fixture { FakeCustomTileStatePersister() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerFactoryKosmos.kt
new file mode 100644
index 000000000000..f8ce707b0bb2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerFactoryKosmos.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.external
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+/** Returns mocks */
+var Kosmos.tileLifecycleManagerFactory: TileLifecycleManager.Factory by
+ Kosmos.Fixture { TileLifecycleManager.Factory { _, _ -> mock<TileLifecycleManager>() } }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessorsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessorsKosmos.kt
new file mode 100644
index 000000000000..d93dd8d42721
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessorsKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.pipeline.data.model
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.pipeline.data.restoreprocessors.WorkTileRestoreProcessor
+
+val Kosmos.workTileRestoreProcessor by Kosmos.Fixture { WorkTileRestoreProcessor() }
+
+var Kosmos.restoreProcessors by
+ Kosmos.Fixture {
+ setOf(
+ workTileRestoreProcessor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt
new file mode 100644
index 000000000000..009148266143
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.pipeline.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeTileSpecRepository by Kosmos.Fixture { FakeTileSpecRepository() }
+var Kosmos.tileSpecRepository: TileSpecRepository by Kosmos.Fixture { fakeTileSpecRepository }
+
+val Kosmos.fakeAutoAddRepository by Kosmos.Fixture { FakeAutoAddRepository() }
+var Kosmos.autoAddRepository: AutoAddRepository by Kosmos.Fixture { fakeAutoAddRepository }
+
+val Kosmos.fakeRestoreRepository by Kosmos.Fixture { FakeQSSettingsRestoredRepository() }
+var Kosmos.restoreRepository: QSSettingsRestoredRepository by
+ Kosmos.Fixture { fakeRestoreRepository }
+
+val Kosmos.fakeInstalledTilesRepository by
+ Kosmos.Fixture { FakeInstalledTilesComponentRepository() }
+var Kosmos.installedTilesRepository: InstalledTilesComponentRepository by
+ Kosmos.Fixture { fakeInstalledTilesRepository }
+
+val Kosmos.fakeCustomTileAddedRepository by Kosmos.Fixture { FakeCustomTileAddedRepository() }
+var Kosmos.customTileAddedRepository: CustomTileAddedRepository by
+ Kosmos.Fixture { fakeCustomTileAddedRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddablesKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddablesKosmos.kt
new file mode 100644
index 000000000000..35f178b62a08
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddablesKosmos.kt
@@ -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.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.pipeline.data.model.workTileRestoreProcessor
+import com.android.systemui.settings.userTracker
+
+val Kosmos.workTileAutoAddable by
+ Kosmos.Fixture { WorkTileAutoAddable(userTracker, workTileRestoreProcessor) }
+
+var Kosmos.autoAddables by Kosmos.Fixture { setOf(workTileAutoAddable) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt
index ebdd6fd7aac0..bf8f4da34d5b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt
@@ -39,14 +39,18 @@ class FakeAutoAddable(
return getFlow(userId).asStateFlow().filterNotNull()
}
- suspend fun sendRemoveSignal(userId: Int) {
+ fun sendRemoveSignal(userId: Int) {
getFlow(userId).value = AutoAddSignal.Remove(spec)
}
- suspend fun sendAddSignal(userId: Int, position: Int = POSITION_AT_END) {
+ fun sendAddSignal(userId: Int, position: Int = POSITION_AT_END) {
getFlow(userId).value = AutoAddSignal.Add(spec, position)
}
+ fun sendRemoveTrackingSignal(userId: Int) {
+ getFlow(userId).value = AutoAddSignal.RemoveTracking(spec)
+ }
+
override val description: String
get() = "FakeAutoAddable($spec)"
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorKosmos.kt
new file mode 100644
index 000000000000..5e8471c5575b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorKosmos.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.pipeline.domain.interactor
+
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.qs.pipeline.data.repository.autoAddRepository
+import com.android.systemui.qs.pipeline.domain.autoaddable.autoAddables
+import com.android.systemui.qs.pipeline.shared.logging.qsLogger
+
+val Kosmos.autoAddInteractor by
+ Kosmos.Fixture {
+ AutoAddInteractor(
+ autoAddables,
+ autoAddRepository,
+ dumpManager,
+ qsLogger,
+ applicationCoroutineScope,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorKosmos.kt
new file mode 100644
index 000000000000..67df563ec5b0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorKosmos.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.qs.external.customTileStatePersister
+import com.android.systemui.qs.external.tileLifecycleManagerFactory
+import com.android.systemui.qs.newQSTileFactory
+import com.android.systemui.qs.pipeline.data.repository.customTileAddedRepository
+import com.android.systemui.qs.pipeline.data.repository.installedTilesRepository
+import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
+import com.android.systemui.qs.pipeline.shared.logging.qsLogger
+import com.android.systemui.qs.pipeline.shared.pipelineFlagsRepository
+import com.android.systemui.qs.qsTileFactory
+import com.android.systemui.settings.userTracker
+import com.android.systemui.user.data.repository.userRepository
+
+val Kosmos.currentTilesInteractor: CurrentTilesInteractor by
+ Kosmos.Fixture {
+ CurrentTilesInteractorImpl(
+ tileSpecRepository,
+ installedTilesRepository,
+ userRepository,
+ customTileStatePersister,
+ { newQSTileFactory },
+ qsTileFactory,
+ customTileAddedRepository,
+ tileLifecycleManagerFactory,
+ userTracker,
+ testDispatcher,
+ testDispatcher,
+ applicationCoroutineScope,
+ qsLogger,
+ pipelineFlagsRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorKosmos.kt
new file mode 100644
index 000000000000..55c23d41e548
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorKosmos.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.qs.pipeline.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.qs.pipeline.data.model.restoreProcessors
+import com.android.systemui.qs.pipeline.data.repository.autoAddRepository
+import com.android.systemui.qs.pipeline.data.repository.restoreRepository
+import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
+import com.android.systemui.qs.pipeline.shared.logging.qsLogger
+
+val Kosmos.restoreReconciliationInteractor by
+ Kosmos.Fixture {
+ RestoreReconciliationInteractor(
+ tileSpecRepository,
+ autoAddRepository,
+ restoreRepository,
+ restoreProcessors,
+ qsLogger,
+ applicationCoroutineScope,
+ testDispatcher,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagRepositoryKosmos.kt
new file mode 100644
index 000000000000..961545aba4e8
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagRepositoryKosmos.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.pipeline.shared
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.pipelineFlagsRepository by Kosmos.Fixture { QSPipelineFlagsRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt
new file mode 100644
index 000000000000..7d52f5d8aa34
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.pipeline.shared.logging
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+/** mock */
+var Kosmos.qsLogger: QSPipelineLogger by Kosmos.Fixture { mock<QSPipelineLogger>() }
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/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
index 7494ccf32a2c..2ca338a3af9c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
@@ -72,6 +72,7 @@ class FakeUserTracker(
onBeforeUserSwitching()
onUserChanging()
onUserChanged()
+ onProfileChanged()
}
fun onBeforeUserSwitching(userId: Int = _userId) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserTrackerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserTrackerKosmos.kt
new file mode 100644
index 000000000000..ffa86ff03ab1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserTrackerKosmos.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.settings
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeUserTracker by Kosmos.Fixture { FakeUserTracker() }
+var Kosmos.userTracker: UserTracker by Kosmos.Fixture { fakeUserTracker }
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/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt
index 3403227f6d27..13d577bde711 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.notification.stack.domain.interactor
import android.content.applicationContext
import com.android.systemui.common.ui.data.repository.configurationRepository
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.statusbar.policy.splitShadeStateController
@@ -27,5 +29,7 @@ val Kosmos.sharedNotificationContainerInteractor by
configurationRepository = configurationRepository,
context = applicationContext,
splitShadeStateController = splitShadeStateController,
+ keyguardInteractor = keyguardInteractor,
+ deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
)
}
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/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index 9fcabd67f9dd..13908f1732e1 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -1,8 +1,16 @@
# Only classes listed here can use the Ravenwood annotations.
com.android.internal.util.ArrayUtils
+com.android.internal.os.BatteryStatsHistory
+com.android.internal.os.BatteryStatsHistory$TraceDelegate
+com.android.internal.os.BatteryStatsHistory$VarintParceler
+com.android.internal.os.BatteryStatsHistoryIterator
+com.android.internal.os.Clock
com.android.internal.os.LongArrayMultiStateCounter
com.android.internal.os.LongArrayMultiStateCounter$LongArrayContainer
+com.android.internal.os.MonotonicClock
+com.android.internal.os.PowerStats
+com.android.internal.os.PowerStats$Descriptor
android.util.AtomicFile
android.util.DataUnit
@@ -25,10 +33,15 @@ android.util.TimeUtils
android.util.Xml
android.os.BatteryConsumer
+android.os.BatteryStats$HistoryItem
+android.os.BatteryStats$HistoryStepDetails
+android.os.BatteryStats$HistoryTag
+android.os.BatteryStats$ProcessStateChange
android.os.Binder
android.os.Binder$IdentitySupplier
android.os.Broadcaster
android.os.BundleMerger
+android.os.ConditionVariable
android.os.FileUtils
android.os.FileUtils$MemoryPipe
android.os.Handler
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 0696807b3c8c..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 {
@@ -209,6 +210,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final ComponentName mComponentName;
int mGenericMotionEventSources;
+ int mObservedMotionEventSources;
// the events pending events to be dispatched to this service
final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<>();
@@ -397,6 +399,19 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
mNotificationTimeout = info.notificationTimeout;
mIsDefault = (info.flags & DEFAULT) != 0;
mGenericMotionEventSources = info.getMotionEventSources();
+ if (android.view.accessibility.Flags.motionEventObserving()) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING)
+ == PackageManager.PERMISSION_GRANTED) {
+ mObservedMotionEventSources = info.getObservedMotionEventSources();
+ } else {
+ Slog.e(
+ LOG_TAG,
+ "Observing motion events requires"
+ + " android.Manifest.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING.");
+ mObservedMotionEventSources = 0;
+ }
+ }
if (supportsFlagForNotImportantViews(info)) {
if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) {
@@ -1599,7 +1614,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int displayId = displays[i].getDisplayId();
onDisplayRemoved(displayId);
}
- if (Flags.cleanupA11yOverlays()) {
+ if (com.android.server.accessibility.Flags.cleanupA11yOverlays()) {
detachAllOverlays();
}
}
@@ -1919,6 +1934,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return (mGenericMotionEventSources & eventSourceWithoutClass) != 0;
}
+
/**
* Called by the invocation handler to notify the service that the
* state of magnification has changed.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 6cac6a47c77b..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();
@@ -198,6 +199,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
// State tracking for generic MotionEvents is display-agnostic so we only need one.
private GenericMotionEventStreamState mGenericMotionEventStreamState;
private int mCombinedGenericMotionEventSources = 0;
+ private int mCombinedMotionEventObservedSources = 0;
private EventStreamState mKeyboardStreamState;
@@ -525,16 +527,33 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
if ((mEnabledFeatures & FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS) != 0) {
- addFirstEventHandler(displayId, new BaseEventStreamTransformation() {
- @Override
- public void onMotionEvent(MotionEvent event, MotionEvent rawEvent,
- int policyFlags) {
- if (!anyServiceWantsGenericMotionEvent(rawEvent)
- || !mAms.sendMotionEventToListeningServices(rawEvent)) {
- super.onMotionEvent(event, rawEvent, policyFlags);
- }
- }
- });
+ addFirstEventHandler(
+ displayId,
+ new BaseEventStreamTransformation() {
+ @Override
+ public void onMotionEvent(
+ MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ boolean passAlongEvent = true;
+ if (anyServiceWantsGenericMotionEvent(event)) {
+ // Some service wants this event, so try to deliver it to at least
+ // one service.
+ if (mAms.sendMotionEventToListeningServices(event)) {
+ // A service accepted this event, so prevent it from passing
+ // down the stream by default.
+ passAlongEvent = false;
+ }
+ // However, if a service is observing these events instead of
+ // consuming them then ensure
+ // it is always passed along to the next stage of the event stream.
+ if (anyServiceWantsToObserveMotionEvent(event)) {
+ passAlongEvent = true;
+ }
+ }
+ if (passAlongEvent) {
+ super.onMotionEvent(event, rawEvent, policyFlags);
+ }
+ }
+ });
}
if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
@@ -542,15 +561,14 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
|| ((mEnabledFeatures & FLAG_FEATURE_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP) != 0)
|| ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) {
final MagnificationGestureHandler magnificationGestureHandler =
- createMagnificationGestureHandler(displayId,
- displayContext);
+ createMagnificationGestureHandler(displayId, displayContext);
addFirstEventHandler(displayId, magnificationGestureHandler);
mMagnificationGestureHandler.put(displayId, magnificationGestureHandler);
}
if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
- MotionEventInjector injector = new MotionEventInjector(
- mContext.getMainLooper(), mAms.getTraceManager());
+ MotionEventInjector injector =
+ new MotionEventInjector(mContext.getMainLooper(), mAms.getTraceManager());
addFirstEventHandler(displayId, injector);
mMotionEventInjectors.put(displayId, injector);
}
@@ -923,6 +941,20 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
}
+ private boolean anyServiceWantsToObserveMotionEvent(MotionEvent event) {
+ // Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
+ // touch exploration.
+ if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
+ && (mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
+ return false;
+ }
+ final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
+ return (mCombinedGenericMotionEventSources
+ & mCombinedMotionEventObservedSources
+ & eventSourceWithoutClass)
+ != 0;
+ }
+
private boolean anyServiceWantsGenericMotionEvent(MotionEvent event) {
// Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
// touch exploration.
@@ -938,6 +970,10 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
mCombinedGenericMotionEventSources = sources;
}
+ public void setCombinedMotionEventObservedSources(int sources) {
+ mCombinedMotionEventObservedSources = sources;
+ }
+
/**
* Keeps state of streams of events from all keyboard devices.
*/
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 440e99632c86..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,
@@ -2825,8 +2826,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS;
}
int combinedGenericMotionEventSources = 0;
+ int combinedMotionEventObservedSources = 0;
for (AccessibilityServiceConnection connection : userState.mBoundServices) {
combinedGenericMotionEventSources |= connection.mGenericMotionEventSources;
+ combinedMotionEventObservedSources |= connection.mObservedMotionEventSources;
}
if (combinedGenericMotionEventSources != 0) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS;
@@ -2845,6 +2848,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mInputFilter.setUserAndEnabledFeatures(userState.mUserId, flags);
mInputFilter.setCombinedGenericMotionEventSources(
combinedGenericMotionEventSources);
+ mInputFilter.setCombinedMotionEventObservedSources(
+ combinedMotionEventObservedSources);
} else {
if (mHasInputFilter) {
mHasInputFilter = false;
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/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/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 34787a390d48..145303df7b0b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -554,6 +554,10 @@ final class ContentCapturePerUserService
if (mMaster.debug) Slog.d(mTag, "onActivityEvent(): no remote service");
return;
}
+ if (mRemoteService.getServiceInterface() == null) {
+ if (mMaster.debug) Slog.d(mTag, "onActivityEvent(): remote service is dead or unbound");
+ return;
+ }
final ActivityEvent event = new ActivityEvent(activityId, componentName, type);
if (mMaster.verbose) Slog.v(mTag, "onActivityEvent(): " + event);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 20a3b9ada85d..a0ccbf3acf0a 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -154,6 +154,7 @@ java_library_static {
static_libs: [
"android.frameworks.location.altitude-V1-java", // AIDL
+ "android.frameworks.vibrator-V1-java", // AIDL
"android.hardware.authsecret-V1.0-java",
"android.hardware.authsecret-V1-java",
"android.hardware.boot-V1.0-java", // HIDL
@@ -165,7 +166,7 @@ java_library_static {
"android.hardware.health-V1.0-java", // HIDL
"android.hardware.health-V2.0-java", // HIDL
"android.hardware.health-V2.1-java", // HIDL
- "android.hardware.health-V2-java", // AIDL
+ "android.hardware.health-V3-java", // AIDL
"android.hardware.health-translate-java",
"android.hardware.light-V1-java",
"android.hardware.security.rkp-V3-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 09e79860b45c..136692eb90d5 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -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/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index f8f3d82556fa..ace2cfd8a307 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -33,6 +33,7 @@ import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.RequiresNoPermission;
import android.annotation.SuppressLint;
+import android.app.AlarmManager;
import android.app.StatsManager;
import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -427,13 +428,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mPowerStatsStore = new PowerStatsStore(systemDir, mHandler, aggregatedPowerStatsConfig);
mPowerStatsAggregator = new PowerStatsAggregator(aggregatedPowerStatsConfig,
mStats.getHistory());
- final long aggregatedPowerStatsSpanDuration = context.getResources().getInteger(
- com.android.internal.R.integer.config_aggregatedPowerStatsSpanDuration);
- final long powerStatsAggregationPeriod = context.getResources().getInteger(
- com.android.internal.R.integer.config_powerStatsAggregationPeriod);
- mPowerStatsScheduler = new PowerStatsScheduler(context, mPowerStatsAggregator,
- aggregatedPowerStatsSpanDuration, powerStatsAggregationPeriod, mPowerStatsStore,
- Clock.SYSTEM_CLOCK, mMonotonicClock, mHandler, mStats);
+ mPowerStatsScheduler = createPowerStatsScheduler(mContext);
PowerStatsExporter powerStatsExporter =
new PowerStatsExporter(mPowerStatsStore, mPowerStatsAggregator);
mBatteryUsageStatsProvider = new BatteryUsageStatsProvider(context,
@@ -445,6 +440,23 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mConfigFile = new AtomicFile(new File(systemDir, "battery_usage_stats_config"));
}
+ private PowerStatsScheduler createPowerStatsScheduler(Context context) {
+ final long aggregatedPowerStatsSpanDuration = context.getResources().getInteger(
+ com.android.internal.R.integer.config_aggregatedPowerStatsSpanDuration);
+ final long powerStatsAggregationPeriod = context.getResources().getInteger(
+ com.android.internal.R.integer.config_powerStatsAggregationPeriod);
+ PowerStatsScheduler.AlarmScheduler alarmScheduler =
+ (triggerAtMillis, tag, onAlarmListener, aHandler) -> {
+ AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
+ alarmManager.set(AlarmManager.ELAPSED_REALTIME, triggerAtMillis, tag,
+ onAlarmListener, aHandler);
+ };
+ return new PowerStatsScheduler(mStats::schedulePowerStatsSampleCollection,
+ mPowerStatsAggregator, aggregatedPowerStatsSpanDuration,
+ powerStatsAggregationPeriod, mPowerStatsStore, alarmScheduler, Clock.SYSTEM_CLOCK,
+ mMonotonicClock, () -> mStats.getHistory().getStartTime(), mHandler);
+ }
+
private AggregatedPowerStatsConfig getAggregatedPowerStatsConfig() {
AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_CPU)
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/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/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/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..769554315b6e 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
@@ -1057,6 +1057,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");
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/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..c440a6461de2 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);
}
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/AudioPoliciesDeviceRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
index 173c452fd8cb..850449595d74 100644
--- a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
+++ b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
@@ -330,8 +330,11 @@ import java.util.Objects;
TextUtils.isEmpty(address)
? null
: mBluetoothRouteController.getRouteIdForBluetoothAddress(address);
- return createMediaRoute2Info(
- routeId, audioDeviceInfo.getType(), audioDeviceInfo.getProductName(), address);
+ // We use the name from the port instead AudioDeviceInfo#getProductName because the latter
+ // replaces empty names with the name of the device (example: Pixel 8). In that case we want
+ // to derive a name ourselves from the type instead.
+ String deviceName = audioDeviceInfo.getPort().name();
+ return createMediaRoute2Info(routeId, audioDeviceInfo.getType(), deviceName, address);
}
/**
@@ -339,8 +342,8 @@ import java.util.Objects;
*
* @param routeId A route id, or null to use an id pre-defined for the given {@code type}.
* @param audioDeviceInfoType The type as obtained from {@link AudioDeviceInfo#getType}.
- * @param productName The product name as obtained from {@link
- * AudioDeviceInfo#getProductName()}, or null to use a predefined name for the given {@code
+ * @param deviceName A human readable name to populate the route's {@link
+ * MediaRoute2Info#getName name}, or null to use a predefined name for the given {@code
* type}.
* @param address The type as obtained from {@link AudioDeviceInfo#getAddress()} or {@link
* BluetoothDevice#getAddress()}.
@@ -350,7 +353,7 @@ import java.util.Objects;
private MediaRoute2Info createMediaRoute2Info(
@Nullable String routeId,
int audioDeviceInfoType,
- @Nullable CharSequence productName,
+ @Nullable CharSequence deviceName,
@Nullable String address) {
SystemRouteInfo systemRouteInfo =
AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.get(audioDeviceInfoType);
@@ -359,7 +362,7 @@ import java.util.Objects;
// earpiece.
return null;
}
- CharSequence humanReadableName = productName;
+ CharSequence humanReadableName = deviceName;
if (TextUtils.isEmpty(humanReadableName)) {
humanReadableName = mContext.getResources().getText(systemRouteInfo.mNameResource);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a62d8b8bc032..66a974080a43 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5406,6 +5406,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 +5464,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");
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/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index dcac8c98d19f..da017453ed8b 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -20,3 +20,17 @@ flag {
description: "This flag controls the refactoring of NMS to NotificationAttentionHelper"
bug: "291907312"
}
+
+flag {
+ name: "cross_app_polite_notifications"
+ namespace: "systemui"
+ description: "This flag controls the cross-app effect of polite notifications"
+ bug: "270456865"
+}
+
+flag {
+ name: "vibrate_while_unlocked"
+ namespace: "systemui"
+ description: "This flag controls the vibrate while unlocked setting of polite notifications"
+ bug: "270456865"
+} \ No newline at end of file
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..27f4e11c53ad 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -508,12 +508,15 @@ 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);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 2dc3fb7464fd..abfd5715810e 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -4980,31 +4980,34 @@ 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
diff --git a/services/core/java/com/android/server/pm/DeletePackageAction.java b/services/core/java/com/android/server/pm/DeletePackageAction.java
index 8ef6601f7684..31544d5308fb 100644
--- a/services/core/java/com/android/server/pm/DeletePackageAction.java
+++ b/services/core/java/com/android/server/pm/DeletePackageAction.java
@@ -16,17 +16,19 @@
package com.android.server.pm;
+import android.annotation.NonNull;
import android.os.UserHandle;
final class DeletePackageAction {
public final PackageSetting mDeletingPs;
public final PackageSetting mDisabledPs;
+ @NonNull
public final PackageRemovedInfo mRemovedInfo;
public final int mFlags;
public final UserHandle mUser;
DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs,
- PackageRemovedInfo removedInfo, int flags, UserHandle user) {
+ @NonNull PackageRemovedInfo removedInfo, int flags, UserHandle user) {
mDeletingPs = deletingPs;
mDisabledPs = disabledPs;
mRemovedInfo = removedInfo;
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 93836266d1f4..aa7f0d3c668a 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -370,7 +370,7 @@ final class DeletePackageHelper {
@GuardedBy("mPm.mInstallLock")
public boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
boolean deleteCodeAndResources, @NonNull int[] allUserHandles, int flags,
- PackageRemovedInfo outInfo, boolean writeSettings) {
+ @NonNull PackageRemovedInfo outInfo, boolean writeSettings) {
final DeletePackageAction action;
synchronized (mPm.mLock) {
final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
@@ -410,8 +410,8 @@ final class DeletePackageHelper {
* deleted, {@code null} otherwise.
*/
@Nullable
- public static DeletePackageAction mayDeletePackageLocked(
- PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs,
+ public static DeletePackageAction mayDeletePackageLocked(@NonNull PackageRemovedInfo outInfo,
+ PackageSetting ps, @Nullable PackageSetting disabledPs,
int flags, UserHandle user) {
if (ps == null) {
return null;
@@ -460,12 +460,18 @@ final class DeletePackageHelper {
}
final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
- if (outInfo != null) {
- // Remember which users are affected, before the installed states are modified
- outInfo.mRemovedUsers = (systemApp || userId == UserHandle.USER_ALL)
- ? ps.queryUsersInstalledOrHasData(allUserHandles)
- : new int[]{userId};
- }
+ // Remember which users are affected, before the installed states are modified
+ outInfo.mRemovedUsers = (systemApp || userId == UserHandle.USER_ALL)
+ ? ps.queryUsersInstalledOrHasData(allUserHandles)
+ : new int[]{userId};
+ outInfo.populateBroadcastUsers(ps);
+ outInfo.mDataRemoved = (flags & PackageManager.DELETE_KEEP_DATA) == 0;
+ outInfo.mRemovedPackage = ps.getPackageName();
+ outInfo.mInstallerPackageName = ps.getInstallSource().mInstallerPackageName;
+ outInfo.mIsStaticSharedLib =
+ ps.getPkg() != null && ps.getPkg().getStaticSharedLibraryName() != null;
+ outInfo.mIsExternal = ps.isExternalStorage();
+ outInfo.mRemovedPackageVersionCode = ps.getVersionCode();
if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)
&& userId != UserHandle.USER_ALL) {
@@ -503,7 +509,11 @@ final class DeletePackageHelper {
}
}
if (clearPackageStateAndReturn) {
- mRemovePackageHelper.clearPackageStateForUserLIF(ps, userId, outInfo, flags);
+ mRemovePackageHelper.clearPackageStateForUserLIF(ps, userId, flags);
+ // 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;
}
@@ -529,12 +539,8 @@ final class DeletePackageHelper {
// If the package removed had SUSPEND_APPS, unset any restrictions that might have been in
// place for all affected users.
- int[] affectedUserIds = (outInfo != null) ? outInfo.mRemovedUsers : null;
- if (affectedUserIds == null) {
- affectedUserIds = mPm.resolveUserIds(userId);
- }
final Computer snapshot = mPm.snapshotComputer();
- for (final int affectedUserId : affectedUserIds) {
+ for (final int affectedUserId : outInfo.mRemovedUsers) {
if (hadSuspendAppsPermission.get(affectedUserId)) {
mPm.unsuspendForSuspendingPackage(snapshot, packageName, affectedUserId);
mPm.removeAllDistractingPackageRestrictions(snapshot, affectedUserId);
@@ -542,24 +548,21 @@ final class DeletePackageHelper {
}
// Take a note whether we deleted the package for all users
- if (outInfo != null) {
- synchronized (mPm.mLock) {
- outInfo.mRemovedForAllUsers = mPm.mPackages.get(ps.getPackageName()) == null;
- }
+ synchronized (mPm.mLock) {
+ outInfo.mRemovedForAllUsers = mPm.mPackages.get(ps.getPackageName()) == null;
}
}
@GuardedBy("mPm.mInstallLock")
private void deleteInstalledPackageLIF(PackageSetting ps,
boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles,
- PackageRemovedInfo outInfo, boolean writeSettings) {
+ @NonNull PackageRemovedInfo outInfo, boolean writeSettings) {
synchronized (mPm.mLock) {
- if (outInfo != null) {
- outInfo.mUid = ps.getAppId();
- outInfo.mBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
- mPm.snapshotComputer(), ps, allUserHandles,
- mPm.mSettings.getPackagesLocked());
- }
+ // 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,
+ mPm.mSettings.getPackagesLocked());
}
// Delete package data from internal structures and also remove data if flag is set
@@ -567,7 +570,7 @@ final class DeletePackageHelper {
ps, allUserHandles, outInfo, flags, writeSettings);
// Delete application code and resources only for parent packages
- if (deleteCodeAndResources && (outInfo != null)) {
+ if (deleteCodeAndResources) {
outInfo.mArgs = new InstallArgs(
ps.getPathString(), getAppDexInstructionSets(
ps.getPrimaryCpuAbiLegacy(), ps.getSecondaryCpuAbiLegacy()));
@@ -639,7 +642,7 @@ final class DeletePackageHelper {
int flags = action.mFlags;
final PackageSetting deletedPs = action.mDeletingPs;
final PackageRemovedInfo outInfo = action.mRemovedInfo;
- final boolean applyUserRestrictions = outInfo != null && (outInfo.mOrigUsers != null);
+ final boolean applyUserRestrictions = outInfo.mOrigUsers != null;
final AndroidPackage deletedPkg = deletedPs.getPkg();
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
@@ -662,10 +665,8 @@ final class DeletePackageHelper {
}
}
- if (outInfo != null) {
- // Delete the updated package
- outInfo.mIsRemovedPackageSystemUpdate = true;
- }
+ // Delete the updated package
+ outInfo.mIsRemovedPackageSystemUpdate = true;
if (disabledPs.getVersionCode() < deletedPs.getVersionCode()
|| disabledPs.getAppId() != deletedPs.getAppId()) {
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 83a6f10f0e2a..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,
@@ -4126,7 +4129,7 @@ final class InstallPackageHelper {
null /* request */)) {
mDeletePackageHelper.deletePackageLIF(
parsedPackage.getPackageName(), null, true,
- mPm.mUserManager.getUserIds(), 0, null, false);
+ mPm.mUserManager.getUserIds(), 0, new PackageRemovedInfo(), false);
}
} else if (newPkgVersionGreater || newSharedUserSetting) {
// The application on /system is newer than the application on /data.
@@ -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..ba66377beb8a 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1575,6 +1575,30 @@ 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 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..6b05edf7c25a 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -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/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..c737b45ae885 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -762,13 +762,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 2880f84c6445..56365b676618 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;
@@ -2013,6 +2013,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
@@ -3044,6 +3054,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
}
+ @NonNull
int[] resolveUserIds(int userId) {
return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
}
@@ -5241,14 +5252,18 @@ 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;
+ }
+ return mSuspendPackageHelper.getSuspendingPackage(snapshot, packageName, userId,
+ callingUid);
+ } catch (PackageManager.NameNotFoundException e) {
return null;
}
- return mSuspendPackageHelper.getSuspendingPackage(snapshot, packageName, userId,
- callingUid);
}
@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..322557b9e496 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -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/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 52b31319cc19..fefab3ba15b9 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,8 +252,7 @@ final class RemovePackageHelper {
}
}
- public void clearPackageStateForUserLIF(PackageSetting ps, int userId,
- PackageRemovedInfo outInfo, int flags) {
+ public void clearPackageStateForUserLIF(PackageSetting ps, int userId, int flags) {
final AndroidPackage pkg;
final SharedUserSetting sus;
synchronized (mPm.mLock) {
@@ -287,25 +286,12 @@ final class RemovePackageHelper {
}
mPermissionManager.onPackageUninstalled(ps.getPackageName(), ps.getAppId(), ps, pkg,
sharedUserPkgs, userId);
-
- if (outInfo != null) {
- if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
- outInfo.mDataRemoved = true;
- }
- outInfo.mRemovedPackage = ps.getPackageName();
- outInfo.mInstallerPackageName = ps.getInstallSource().mInstallerPackageName;
- outInfo.mIsStaticSharedLib = pkg != null && pkg.getStaticSharedLibraryName() != null;
- outInfo.mRemovedAppId = ps.getAppId();
- outInfo.mBroadcastUsers = outInfo.mRemovedUsers;
- outInfo.mIsExternal = ps.isExternalStorage();
- outInfo.mRemovedPackageVersionCode = ps.getVersionCode();
- }
}
// Called to clean up disabled system packages
public void removePackageData(final PackageSetting deletedPs, @NonNull int[] allUserHandles) {
synchronized (mPm.mInstallLock) {
- removePackageDataLIF(deletedPs, allUserHandles, /* outInfo= */ null,
+ removePackageDataLIF(deletedPs, allUserHandles, new PackageRemovedInfo(),
/* flags= */ 0, /* writeSettings= */ false);
}
}
@@ -318,20 +304,11 @@ final class RemovePackageHelper {
*/
@GuardedBy("mPm.mInstallLock")
public void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
- PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
+ @NonNull PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
String packageName = deletedPs.getPackageName();
if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
// Retrieve object to delete permissions for shared user later on
final AndroidPackage deletedPkg = deletedPs.getPkg();
- if (outInfo != null) {
- outInfo.mRemovedPackage = packageName;
- outInfo.mInstallerPackageName = deletedPs.getInstallSource().mInstallerPackageName;
- outInfo.mIsStaticSharedLib = deletedPkg != null
- && deletedPkg.getStaticSharedLibraryName() != null;
- outInfo.populateBroadcastUsers(deletedPs);
- outInfo.mIsExternal = deletedPs.isExternalStorage();
- outInfo.mRemovedPackageVersionCode = deletedPs.getVersionCode();
- }
removePackageLI(deletedPs.getPackageName(), (flags & PackageManager.DELETE_CHATTY) != 0);
if (!deletedPs.isSystem()) {
@@ -355,9 +332,6 @@ final class RemovePackageHelper {
mAppDataHelper.destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
mAppDataHelper.destroyAppProfilesLIF(resolvedPkg.getPackageName());
- if (outInfo != null) {
- outInfo.mDataRemoved = true;
- }
}
int removedAppId = -1;
@@ -373,9 +347,7 @@ final class RemovePackageHelper {
mPm.mAppsFilter.removePackage(snapshot,
snapshot.getPackageStateInternal(packageName));
removedAppId = mPm.mSettings.removePackageLPw(packageName);
- if (outInfo != null) {
- outInfo.mRemovedAppId = removedAppId;
- }
+ outInfo.mIsAppIdRemoved = true;
if (!mPm.mSettings.isDisabledSystemPackageLPr(packageName)) {
// If we don't have a disabled system package to reinstall, the package is
// really gone and its permission state should be removed.
@@ -403,8 +375,8 @@ final class RemovePackageHelper {
mBroadcastHelper.sendPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
});
}
- } else if (!deletedPs.isSystem() && outInfo != null && !outInfo.mIsUpdate
- && outInfo.mRemovedUsers != null && !outInfo.mIsExternal) {
+ } 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
// for affected users. This does not apply to app updates where the old apk is replaced
// but the old data remains.
@@ -424,7 +396,7 @@ final class RemovePackageHelper {
// 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;
- if (outInfo != null && outInfo.mOrigUsers != null && deletedPs.isSystem()) {
+ if (outInfo.mOrigUsers != null && deletedPs.isSystem()) {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across downgrade");
}
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..cfbaae3d0f30 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -89,6 +89,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 +107,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;
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 94495bf462f2..ec8af2ecd070 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -731,7 +731,7 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable
? PackageManager.DELETE_KEEP_DATA : 0;
synchronized (mPm.mInstallLock) {
mDeletePackageHelper.deletePackageLIF(pkg.getPackageName(), null, true,
- mPm.mUserManager.getUserIds(), flags, null,
+ mPm.mUserManager.getUserIds(), flags, new PackageRemovedInfo(),
true);
}
}
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 70aa19ae9cef..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;
@@ -256,13 +256,12 @@ public final class StorageEventHelper extends StorageEventListener {
final AndroidPackage pkg = ps.getPkg();
final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
- final PackageRemovedInfo outInfo = new PackageRemovedInfo();
try (PackageFreezer freezer = mPm.freezePackageForDelete(ps.getPackageName(),
UserHandle.USER_ALL, deleteFlags,
"unloadPrivatePackagesInner", ApplicationExitInfo.REASON_OTHER)) {
if (mDeletePackageHelper.deletePackageLIF(ps.getPackageName(), null, false,
- userIds, deleteFlags, outInfo, false)) {
+ userIds, deleteFlags, new PackageRemovedInfo(), false)) {
unloaded.add(pkg);
} else {
Slog.w(TAG, "Failed to unload " + ps.getPath());
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index fe8c12c8e232..c2a960a95394 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -418,11 +418,24 @@ public final class SuspendPackageHelper {
}
String suspendingPackage = null;
+ String suspendedBySystem = null;
+ String qasPackage = null;
for (int i = 0; i < userState.getSuspendParams().size(); i++) {
suspendingPackage = userState.getSuspendParams().keyAt(i);
+ var suspendParams = userState.getSuspendParams().valueAt(i);
if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
- return suspendingPackage;
+ 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;
}
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..fa54f0ba18cd 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -52,6 +52,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 +66,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 +79,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 +274,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 +294,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 +310,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 +327,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);
}
@@ -923,7 +924,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 +965,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/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/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/power/stats/PowerStatsCollector.java b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
index abfe9debc7de..e1eb8f07dd2c 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
@@ -20,7 +20,6 @@ import android.annotation.Nullable;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.PersistableBundle;
-import android.util.FastImmutableArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -30,8 +29,9 @@ import com.android.internal.os.PowerStats;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.function.Consumer;
-import java.util.stream.Stream;
/**
* Collects snapshots of power-related system statistics.
@@ -246,8 +246,7 @@ public abstract class PowerStatsCollector {
@GuardedBy("this")
@SuppressWarnings("unchecked")
- private volatile FastImmutableArraySet<Consumer<PowerStats>> mConsumerList =
- new FastImmutableArraySet<Consumer<PowerStats>>(new Consumer[0]);
+ private volatile List<Consumer<PowerStats>> mConsumerList = Collections.emptyList();
public PowerStatsCollector(Handler handler, long throttlePeriodMs, Clock clock) {
mHandler = handler;
@@ -262,9 +261,13 @@ public abstract class PowerStatsCollector {
@SuppressWarnings("unchecked")
public void addConsumer(Consumer<PowerStats> consumer) {
synchronized (this) {
- mConsumerList = new FastImmutableArraySet<Consumer<PowerStats>>(
- Stream.concat(mConsumerList.stream(), Stream.of(consumer))
- .toArray(Consumer[]::new));
+ if (mConsumerList.contains(consumer)) {
+ return;
+ }
+
+ List<Consumer<PowerStats>> newList = new ArrayList<>(mConsumerList);
+ newList.add(consumer);
+ mConsumerList = Collections.unmodifiableList(newList);
}
}
@@ -275,9 +278,9 @@ public abstract class PowerStatsCollector {
@SuppressWarnings("unchecked")
public void removeConsumer(Consumer<PowerStats> consumer) {
synchronized (this) {
- mConsumerList = new FastImmutableArraySet<Consumer<PowerStats>>(
- mConsumerList.stream().filter(c -> c != consumer)
- .toArray(Consumer[]::new));
+ List<Consumer<PowerStats>> newList = new ArrayList<>(mConsumerList);
+ newList.remove(consumer);
+ mConsumerList = Collections.unmodifiableList(newList);
}
}
@@ -302,8 +305,9 @@ public abstract class PowerStatsCollector {
if (stats == null) {
return;
}
- for (Consumer<PowerStats> consumer : mConsumerList) {
- consumer.accept(stats);
+ List<Consumer<PowerStats>> consumerList = mConsumerList;
+ for (int i = consumerList.size() - 1; i >= 0; i--) {
+ consumerList.get(i).accept(stats);
}
}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsScheduler.java b/services/core/java/com/android/server/power/stats/PowerStatsScheduler.java
index 97d872a1a539..121a98bab37a 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsScheduler.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsScheduler.java
@@ -18,7 +18,6 @@ package com.android.server.power.stats;
import android.annotation.DurationMillisLong;
import android.app.AlarmManager;
-import android.content.Context;
import android.os.ConditionVariable;
import android.os.Handler;
import android.util.IndentingPrintWriter;
@@ -30,6 +29,7 @@ import com.android.internal.os.MonotonicClock;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
/**
* Controls the frequency at which {@link PowerStatsSpan}'s are generated and stored in
@@ -39,7 +39,7 @@ public class PowerStatsScheduler {
private static final long MINUTE_IN_MILLIS = TimeUnit.MINUTES.toMillis(1);
private static final long HOUR_IN_MILLIS = TimeUnit.HOURS.toMillis(1);
- private final Context mContext;
+ private final AlarmScheduler mAlarmScheduler;
private boolean mEnablePeriodicPowerStatsCollection;
@DurationMillisLong
private final long mAggregatedPowerStatsSpanDuration;
@@ -49,24 +49,38 @@ public class PowerStatsScheduler {
private final Clock mClock;
private final MonotonicClock mMonotonicClock;
private final Handler mHandler;
- private final BatteryStatsImpl mBatteryStats;
+ private final Runnable mPowerStatsCollector;
+ private final Supplier<Long> mEarliestAvailableBatteryHistoryTimeMs;
private final PowerStatsAggregator mPowerStatsAggregator;
private long mLastSavedSpanEndMonotonicTime;
- public PowerStatsScheduler(Context context, PowerStatsAggregator powerStatsAggregator,
+ /**
+ * External dependency on AlarmManager.
+ */
+ public interface AlarmScheduler {
+ /**
+ * Should use AlarmManager to schedule an inexact, non-wakeup alarm.
+ */
+ void scheduleAlarm(long triggerAtMillis, String tag,
+ AlarmManager.OnAlarmListener onAlarmListener, Handler handler);
+ }
+
+ public PowerStatsScheduler(Runnable powerStatsCollector,
+ PowerStatsAggregator powerStatsAggregator,
@DurationMillisLong long aggregatedPowerStatsSpanDuration,
@DurationMillisLong long powerStatsAggregationPeriod, PowerStatsStore powerStatsStore,
- Clock clock, MonotonicClock monotonicClock, Handler handler,
- BatteryStatsImpl batteryStats) {
- mContext = context;
+ AlarmScheduler alarmScheduler, Clock clock, MonotonicClock monotonicClock,
+ Supplier<Long> earliestAvailableBatteryHistoryTimeMs, Handler handler) {
mPowerStatsAggregator = powerStatsAggregator;
mAggregatedPowerStatsSpanDuration = aggregatedPowerStatsSpanDuration;
mPowerStatsAggregationPeriod = powerStatsAggregationPeriod;
mPowerStatsStore = powerStatsStore;
+ mAlarmScheduler = alarmScheduler;
mClock = clock;
mMonotonicClock = monotonicClock;
mHandler = handler;
- mBatteryStats = batteryStats;
+ mPowerStatsCollector = powerStatsCollector;
+ mEarliestAvailableBatteryHistoryTimeMs = earliestAvailableBatteryHistoryTimeMs;
}
/**
@@ -81,9 +95,8 @@ public class PowerStatsScheduler {
}
private void scheduleNextPowerStatsAggregation() {
- AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
- alarmManager.set(AlarmManager.ELAPSED_REALTIME,
- mClock.elapsedRealtime() + mPowerStatsAggregationPeriod, "PowerStats",
+ mAlarmScheduler.scheduleAlarm(mClock.elapsedRealtime() + mPowerStatsAggregationPeriod,
+ "PowerStats",
() -> {
schedulePowerStatsAggregation();
mHandler.post(this::scheduleNextPowerStatsAggregation);
@@ -96,7 +109,7 @@ public class PowerStatsScheduler {
@VisibleForTesting
public void schedulePowerStatsAggregation() {
// Catch up the power stats collectors
- mBatteryStats.schedulePowerStatsSampleCollection();
+ mPowerStatsCollector.run();
mHandler.post(this::aggregateAndStorePowerStats);
}
@@ -105,7 +118,7 @@ public class PowerStatsScheduler {
long currentMonotonicTime = mMonotonicClock.monotonicTime();
long startTime = getLastSavedSpanEndMonotonicTime();
if (startTime < 0) {
- startTime = mBatteryStats.getHistory().getStartTime();
+ startTime = mEarliestAvailableBatteryHistoryTimeMs.get();
}
long endTimeMs = alignToWallClock(startTime + mAggregatedPowerStatsSpanDuration,
mAggregatedPowerStatsSpanDuration, currentMonotonicTime, currentTimeMillis);
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/vibrator/VibratorControlService.java b/services/core/java/com/android/server/vibrator/VibratorControlService.java
new file mode 100644
index 000000000000..2eeb903bb551
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibratorControlService.java
@@ -0,0 +1,105 @@
+/*
+ * 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.vibrator;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.frameworks.vibrator.IVibratorControlService;
+import android.frameworks.vibrator.IVibratorController;
+import android.frameworks.vibrator.VibrationParam;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.Objects;
+
+/**
+ * Implementation of {@link IVibratorControlService} which allows the registration of
+ * {@link IVibratorController} to set and receive vibration params.
+ *
+ * @hide
+ */
+public final class VibratorControlService extends IVibratorControlService.Stub {
+ private static final String TAG = "VibratorControlService";
+
+ private final VibratorControllerHolder mVibratorControllerHolder;
+ private final Object mLock;
+
+ public VibratorControlService(VibratorControllerHolder vibratorControllerHolder, Object lock) {
+ mVibratorControllerHolder = vibratorControllerHolder;
+ mLock = lock;
+ }
+
+ @Override
+ public void registerVibratorController(IVibratorController controller)
+ throws RemoteException {
+ synchronized (mLock) {
+ mVibratorControllerHolder.setVibratorController(controller);
+ }
+ }
+
+ @Override
+ public void unregisterVibratorController(@NonNull IVibratorController controller)
+ throws RemoteException {
+ Objects.requireNonNull(controller);
+
+ synchronized (mLock) {
+ if (mVibratorControllerHolder.getVibratorController() == null) {
+ Slog.w(TAG, "Received request to unregister IVibratorController = "
+ + controller + ", but no controller was previously registered. Request "
+ + "Ignored.");
+ return;
+ }
+ if (!Objects.equals(mVibratorControllerHolder.getVibratorController().asBinder(),
+ controller.asBinder())) {
+ Slog.wtf(TAG, "Failed to unregister IVibratorController. The provided "
+ + "controller doesn't match the registered one. " + this);
+ return;
+ }
+ mVibratorControllerHolder.setVibratorController(null);
+ }
+ }
+
+ @Override
+ public void setVibrationParams(
+ @SuppressLint("ArrayReturn") VibrationParam[] params, IVibratorController token)
+ throws RemoteException {
+ // TODO(b/305939964): Add set vibration implementation.
+ }
+
+ @Override
+ public void clearVibrationParams(int types, IVibratorController token) throws RemoteException {
+ // TODO(b/305939964): Add clear vibration implementation.
+ }
+
+ @Override
+ public void onRequestVibrationParamsComplete(
+ IBinder requestToken, @SuppressLint("ArrayReturn") VibrationParam[] result)
+ throws RemoteException {
+ // TODO(305942827): Cache the vibration params in VibrationScaler
+ }
+
+ @Override
+ public int getInterfaceVersion() throws RemoteException {
+ return this.VERSION;
+ }
+
+ @Override
+ public String getInterfaceHash() throws RemoteException {
+ return this.HASH;
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java b/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java
new file mode 100644
index 000000000000..63e69db9480f
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java
@@ -0,0 +1,70 @@
+/*
+ * 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.vibrator;
+
+import android.annotation.NonNull;
+import android.frameworks.vibrator.IVibratorController;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * Holder class for {@link IVibratorController}.
+ *
+ * @hide
+ */
+public final class VibratorControllerHolder implements IBinder.DeathRecipient {
+ private static final String TAG = "VibratorControllerHolder";
+
+ private IVibratorController mVibratorController;
+
+ public IVibratorController getVibratorController() {
+ return mVibratorController;
+ }
+
+ /**
+ * Sets the {@link IVibratorController} in {@link VibratorControllerHolder} to the new
+ * controller. This will also take care of registering and unregistering death notifications
+ * for the cached {@link IVibratorController}.
+ */
+ public void setVibratorController(IVibratorController controller) {
+ try {
+ if (mVibratorController != null) {
+ mVibratorController.asBinder().unlinkToDeath(this, 0);
+ }
+ mVibratorController = controller;
+ if (mVibratorController != null) {
+ mVibratorController.asBinder().linkToDeath(this, 0);
+ }
+ } catch (RemoteException e) {
+ Slog.wtf(TAG, "Failed to set IVibratorController: " + this, e);
+ }
+ }
+
+ @Override
+ public void binderDied(@NonNull IBinder deadBinder) {
+ if (deadBinder == mVibratorController.asBinder()) {
+ setVibratorController(null);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ // Should not be used as binderDied(IBinder who) is overridden.
+ Slog.wtf(TAG, "binderDied() called unexpectedly.");
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 7d4bd3baf613..fc824abd80f5 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -91,6 +91,8 @@ import java.util.function.Function;
public class VibratorManagerService extends IVibratorManagerService.Stub {
private static final String TAG = "VibratorManagerService";
private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
+ private static final String VIBRATOR_CONTROL_SERVICE =
+ "android.frameworks.vibrator.IVibratorControlService/default";
private static final boolean DEBUG = false;
private static final VibrationAttributes DEFAULT_ATTRIBUTES =
new VibrationAttributes.Builder().build();
@@ -269,6 +271,11 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
+ if (ServiceManager.isDeclared(VIBRATOR_CONTROL_SERVICE)) {
+ injector.addService(VIBRATOR_CONTROL_SERVICE,
+ new VibratorControlService(new VibratorControllerHolder(), mLock));
+ }
+
}
/** Finish initialization at boot phase {@link SystemService#PHASE_SYSTEM_SERVICES_READY}. */
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/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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 03d6c2cab828..ae10ce3690aa 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5149,8 +5149,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/** @return the orientation of the display when it's rotation is ROTATION_0. */
int getNaturalOrientation() {
- return mBaseDisplayWidth < mBaseDisplayHeight
- ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+ final Configuration config = getConfiguration();
+ if (config.windowConfiguration.getDisplayRotation() == ROTATION_0) {
+ return config.orientation;
+ }
+ final Rect frame = mDisplayPolicy.getDecorInsetsInfo(
+ ROTATION_0, mBaseDisplayWidth, mBaseDisplayHeight).mConfigFrame;
+ return frame.width() <= frame.height() ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
}
void performLayout(boolean initial, boolean updateInputWindows) {
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/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/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index a872fd0baaae..4b99432b2943 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -63,6 +63,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_SHORTCUT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
@@ -1178,6 +1179,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mService.mRootWindowContainer.moveActivityToPinnedRootTask(
pipActivity, null /* launchIntoPipHostActivity */,
"moveActivityToPinnedRootTask", null /* transition */, entryBounds);
+
+ // Continue the pausing process after potential task reparenting.
+ if (pipActivity.isState(PAUSING) && pipActivity.mPauseSchedulePendingForPip) {
+ pipActivity.getTask().schedulePauseActivity(
+ pipActivity, false /* userLeaving */,
+ false /* pauseImmediately */, true /* autoEnteringPip */, "auto-pip");
+ }
+
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index fd5f7a3f5cfa..5721750fbf63 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -66,6 +66,7 @@ import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Build;
+import android.os.DeadObjectException;
import android.os.FactoryTest;
import android.os.LocaleList;
import android.os.Message;
@@ -1675,6 +1676,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
@NonNull ClientTransactionItem transactionItem) {
try {
mAtm.getLifecycleManager().scheduleTransactionItem(thread, transactionItem);
+ } catch (DeadObjectException e) {
+ // Expected if the process has been killed.
+ Slog.w(TAG_CONFIGURATION, "Failed for dead process. ClientTransactionItem="
+ + transactionItem + " owner=" + mOwner);
} catch (Exception e) {
Slog.e(TAG_CONFIGURATION, "Failed to schedule ClientTransactionItem="
+ transactionItem + " owner=" + mOwner, e);
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/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
index 47c2a1b079f8..29e258cc90ff 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
@@ -5,4 +5,12 @@ flag {
namespace: "display_manager"
description: "Feature flag for dual display blocking"
bug: "278667199"
+}
+
+flag {
+ name: "enable_foldables_posture_based_closed_state"
+ namespace: "windowing_frontend"
+ description: "Enables smarter closed device state state for foldable devices"
+ bug: "309792734"
+ is_fixed_read_only: true
} \ No newline at end of file
diff --git a/services/manifest_services.xml b/services/manifest_services.xml
index 76389154a885..eae159fe9e89 100644
--- a/services/manifest_services.xml
+++ b/services/manifest_services.xml
@@ -4,4 +4,9 @@
<version>1</version>
<fqname>IAltitudeService/default</fqname>
</hal>
+ <hal format="aidl">
+ <name>android.frameworks.vibrator</name>
+ <version>1</version>
+ <fqname>IVibratorControlService/default</fqname>
+ </hal>
</manifest>
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..b396cf498a67 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
@@ -63,10 +63,10 @@ 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.permission.LegacyPermissionDataProvider;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.ArchiveState;
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/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/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..ae53e707a7cc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -283,6 +283,72 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
}
@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 */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ false /* quarantined */)
+ assertThat(failedNames).isEmpty()
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+
+ // Suspend by system.
+ failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+ targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
+ null /* dialogInfo */, PLATFORM_PACKAGE_NAME, TEST_USER_ID, deviceOwnerUid,
+ false /* quarantined */)
+ assertThat(failedNames).isEmpty()
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(PLATFORM_PACKAGE_NAME)
+
+ // QAS by package1.
+ failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+ targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
+ null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid,
+ true /* quarantined */)
+ assertThat(failedNames).isEmpty()
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(TEST_PACKAGE_1)
+
+ // Un-QAS by package1.
+ suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
+ targetPackages, { suspendingPackage -> suspendingPackage == TEST_PACKAGE_1 },
+ TEST_USER_ID)
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(PLATFORM_PACKAGE_NAME)
+
+ // Un-suspend by system.
+ suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
+ targetPackages, { suspendingPackage -> suspendingPackage == PLATFORM_PACKAGE_NAME },
+ TEST_USER_ID)
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+
+ // Unsuspend.
+ suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
+ targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE },
+ TEST_USER_ID)
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
+ }
+
+ @Test
fun getSuspendedDialogInfo() {
val dialogInfo = SuspendDialogInfo.Builder()
.setTitle(TEST_PACKAGE_1).build()
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
index 07197b1ab9df..05e0e8f4a4f7 100644
--- a/services/tests/powerstatstests/Android.bp
+++ b/services/tests/powerstatstests/Android.bp
@@ -3,6 +3,20 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
+filegroup {
+ name: "power_stats_ravenwood_tests",
+ srcs: [
+ "src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java",
+ "src/com/android/server/power/stats/AggregatedPowerStatsTest.java",
+ "src/com/android/server/power/stats/MultiStateStatsTest.java",
+ "src/com/android/server/power/stats/PowerStatsAggregatorTest.java",
+ "src/com/android/server/power/stats/PowerStatsCollectorTest.java",
+ "src/com/android/server/power/stats/PowerStatsSchedulerTest.java",
+ "src/com/android/server/power/stats/PowerStatsStoreTest.java",
+ "src/com/android/server/power/stats/PowerStatsUidResolverTest.java",
+ ],
+}
+
android_test {
name: "PowerStatsTests",
@@ -12,8 +26,7 @@ android_test {
],
exclude_srcs: [
- "src/com/android/server/power/stats/MultiStateStatsTest.java",
- "src/com/android/server/power/stats/PowerStatsStoreTest.java",
+ ":power_stats_ravenwood_tests",
],
static_libs: [
@@ -65,10 +78,12 @@ android_ravenwood_test {
"modules-utils-binary-xml",
"androidx.annotation_annotation",
"androidx.test.rules",
+ "truth",
+ "mockito_ravenwood",
],
srcs: [
- "src/com/android/server/power/stats/MultiStateStatsTest.java",
- "src/com/android/server/power/stats/PowerStatsStoreTest.java",
+ ":power_stats_ravenwood_tests",
+ "src/com/android/server/power/stats/MockClock.java",
],
auto_gen_config: true,
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatePowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java
index 6d61dc8d31fa..af83be04db7d 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatePowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java
@@ -35,7 +35,7 @@ import java.util.Objects;
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class AggregatePowerStatsProcessorTest {
+public class AggregatedPowerStatsProcessorTest {
@Test
public void createPowerEstimationPlan_allDeviceStatesPresentInUidStates() {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
index e8f46b30fb8c..1b045c532759 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
@@ -22,12 +22,10 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
import android.os.BatteryConsumer;
-import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,11 +36,6 @@ import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MultiStateStatsTest {
-
- @Rule
- public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
- .build();
-
public static final int DIMENSION_COUNT = 2;
@Test
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
index 67049871f396..2456636970fa 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
@@ -24,7 +24,6 @@ import static org.mockito.Mockito.mock;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.PersistableBundle;
-import android.text.format.DateFormat;
import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
@@ -39,7 +38,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.text.ParseException;
-import java.util.Calendar;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.List;
import java.util.TimeZone;
@@ -60,7 +60,7 @@ public class PowerStatsAggregatorTest {
public void setup() throws ParseException {
mHistory = new BatteryStatsHistory(32, 1024,
mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class), mClock,
- mMonotonicClock);
+ mMonotonicClock, mock(BatteryStatsHistory.TraceDelegate.class));
AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
config.trackPowerComponent(TEST_POWER_COMPONENT)
@@ -179,9 +179,9 @@ public class PowerStatsAggregatorTest {
@NonNull
private static CharSequence formatDateTime(long timeInMillis) {
- Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
- cal.setTimeInMillis(timeInMillis);
- return DateFormat.format("yyyy-MM-dd hh:mm:ss", cal);
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
+ format.getCalendar().setTimeZone(TimeZone.getTimeZone("GMT"));
+ return format.format(new Date(timeInMillis));
}
@Test
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java
index 330f698277f8..17a7d3ecf9d3 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java
@@ -22,6 +22,7 @@ import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.PersistableBundle;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +30,18 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.PowerStats;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PowerStatsCollectorTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
private final MockClock mMockClock = new MockClock();
private final HandlerThread mHandlerThread = new HandlerThread("test");
private Handler mHandler;
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsSchedulerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsSchedulerTest.java
index 7257a94cbb9a..beec66156fe4 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsSchedulerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsSchedulerTest.java
@@ -24,26 +24,26 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import android.content.Context;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
+import android.platform.test.ravenwood.RavenwoodRule;
-import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.MonotonicClock;
-import com.android.internal.os.PowerProfile;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
import java.time.Duration;
import java.time.Instant;
+import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
@@ -51,39 +51,46 @@ import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
public class PowerStatsSchedulerTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
private PowerStatsStore mPowerStatsStore;
private Handler mHandler;
private MockClock mClock = new MockClock();
private MonotonicClock mMonotonicClock = new MonotonicClock(0, mClock);
- private MockBatteryStatsImpl mBatteryStats;
private PowerStatsScheduler mPowerStatsScheduler;
- private PowerProfile mPowerProfile;
private PowerStatsAggregator mPowerStatsAggregator;
private AggregatedPowerStatsConfig mAggregatedPowerStatsConfig;
+ private List<Long> mScheduledAlarms = new ArrayList<>();
+ private boolean mPowerStatsCollectionOccurred;
+
+ private static final int START_REALTIME = 7654321;
@Before
@SuppressWarnings("GuardedBy")
- public void setup() {
- final Context context = InstrumentationRegistry.getContext();
-
+ public void setup() throws IOException {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
mClock.currentTime = Instant.parse("2023-01-02T03:04:05.00Z").toEpochMilli();
- mClock.realtime = 7654321;
+ mClock.realtime = START_REALTIME;
HandlerThread bgThread = new HandlerThread("bg thread");
bgThread.start();
- File systemDir = context.getCacheDir();
mHandler = new Handler(bgThread.getLooper());
mAggregatedPowerStatsConfig = new AggregatedPowerStatsConfig();
- mPowerStatsStore = new PowerStatsStore(systemDir, mHandler, mAggregatedPowerStatsConfig);
- mPowerProfile = mock(PowerProfile.class);
- when(mPowerProfile.getAveragePower(PowerProfile.POWER_FLASHLIGHT)).thenReturn(1000000.0);
- mBatteryStats = new MockBatteryStatsImpl(mClock).setPowerProfile(mPowerProfile);
+ mPowerStatsStore = new PowerStatsStore(
+ Files.createTempDirectory("PowerStatsSchedulerTest").toFile(),
+ mHandler, mAggregatedPowerStatsConfig);
mPowerStatsAggregator = mock(PowerStatsAggregator.class);
- mPowerStatsScheduler = new PowerStatsScheduler(context, mPowerStatsAggregator,
- TimeUnit.MINUTES.toMillis(30), TimeUnit.HOURS.toMillis(1), mPowerStatsStore, mClock,
- mMonotonicClock, mHandler, mBatteryStats);
+ mPowerStatsScheduler = new PowerStatsScheduler(
+ () -> mPowerStatsCollectionOccurred = true,
+ mPowerStatsAggregator, TimeUnit.MINUTES.toMillis(30), TimeUnit.HOURS.toMillis(1),
+ mPowerStatsStore,
+ ((triggerAtMillis, tag, onAlarmListener, handler) ->
+ mScheduledAlarms.add(triggerAtMillis)),
+ mClock, mMonotonicClock, () -> 12345L, mHandler);
}
@Test
@@ -113,7 +120,7 @@ public class PowerStatsSchedulerTest {
long endTimeWallClock =
mClock.currentTime - (mMonotonicClock.monotonicTime() - endTime);
- assertThat(startTime).isEqualTo(7654321 + 123);
+ assertThat(startTime).isEqualTo(START_REALTIME + 123);
assertThat(endTime - startTime).isAtLeast(TimeUnit.MINUTES.toMillis(30));
assertThat(Instant.ofEpochMilli(endTimeWallClock))
.isEqualTo(Instant.parse("2023-01-02T04:00:00Z"));
@@ -142,11 +149,15 @@ public class PowerStatsSchedulerTest {
}).when(mPowerStatsAggregator).aggregatePowerStats(anyLong(), anyLong(),
any(Consumer.class));
- mPowerStatsScheduler.schedulePowerStatsAggregation();
+ mPowerStatsScheduler.start(/*enabled*/ true);
ConditionVariable done = new ConditionVariable();
mHandler.post(done::open);
done.block();
+ assertThat(mPowerStatsCollectionOccurred).isTrue();
+ assertThat(mScheduledAlarms).containsExactly(
+ START_REALTIME + TimeUnit.MINUTES.toMillis(90) + TimeUnit.HOURS.toMillis(1));
+
verify(mPowerStatsAggregator, times(2))
.aggregatePowerStats(anyLong(), anyLong(), any(Consumer.class));
@@ -155,7 +166,7 @@ public class PowerStatsSchedulerTest {
// Skip the first entry, which was placed in the store at the beginning of this test
PowerStatsSpan.TimeFrame timeFrame1 = contents.get(1).getTimeFrames().get(0);
PowerStatsSpan.TimeFrame timeFrame2 = contents.get(2).getTimeFrames().get(0);
- assertThat(timeFrame1.startMonotonicTime).isEqualTo(7654321 + 123);
+ assertThat(timeFrame1.startMonotonicTime).isEqualTo(START_REALTIME + 123);
assertThat(timeFrame2.startMonotonicTime)
.isEqualTo(timeFrame1.startMonotonicTime + timeFrame1.duration);
assertThat(Instant.ofEpochMilli(timeFrame2.startTime))
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/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 4a537dfaf8b3..14b551ae0b22 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -211,6 +211,9 @@ 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;
@@ -281,6 +284,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 +317,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 +336,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();
@@ -621,10 +629,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
});
// TODO (b/291907312): remove feature flag
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_VISIT_RISKY_URIS);
- mSetFlagsRule.disableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
mSetFlagsRule.disableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER,
- Flags.FLAG_POLITE_NOTIFICATIONS, android.app.Flags.FLAG_MODES_API);
+ Flags.FLAG_POLITE_NOTIFICATIONS);
initNMS();
}
@@ -6274,21 +6280,15 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(visitor, times(1)).accept(eq(personIcon3.getUri()));
}
- private PendingIntent getPendingIntentWithUri(Uri uri) {
- return PendingIntent.getActivity(mContext, 0,
- new Intent("action", uri),
- PendingIntent.FLAG_IMMUTABLE);
- }
-
@Test
- public void testVisitUris_callStyle_ongoingCall() {
+ public void testVisitUris_callStyle() {
Icon personIcon = Icon.createWithContentUri("content://media/person");
Icon verificationIcon = Icon.createWithContentUri("content://media/verification");
Person callingPerson = new Person.Builder().setName("Someone")
.setIcon(personIcon)
.build();
- Uri hangUpUri = Uri.parse("content://intent/hangup");
- PendingIntent hangUpIntent = getPendingIntentWithUri(hangUpUri);
+ PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
Notification n = new Notification.Builder(mContext, "a")
.setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent)
.setVerificationIcon(verificationIcon))
@@ -6301,35 +6301,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(visitor, times(1)).accept(eq(personIcon.getUri()));
verify(visitor, times(1)).accept(eq(verificationIcon.getUri()));
- verify(visitor, times(1)).accept(eq(hangUpUri));
- }
-
- @Test
- public void testVisitUris_callStyle_incomingCall() {
- Icon personIcon = Icon.createWithContentUri("content://media/person");
- Icon verificationIcon = Icon.createWithContentUri("content://media/verification");
- Person callingPerson = new Person.Builder().setName("Someone")
- .setIcon(personIcon)
- .build();
- Uri answerUri = Uri.parse("content://intent/answer");
- PendingIntent answerIntent = getPendingIntentWithUri(answerUri);
- Uri declineUri = Uri.parse("content://intent/decline");
- PendingIntent declineIntent = getPendingIntentWithUri(declineUri);
- Notification n = new Notification.Builder(mContext, "a")
- .setStyle(Notification.CallStyle.forIncomingCall(callingPerson, declineIntent,
- answerIntent)
- .setVerificationIcon(verificationIcon))
- .setContentTitle("Calling...")
- .setSmallIcon(android.R.drawable.sym_def_app_icon)
- .build();
-
- Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
- n.visitUris(visitor);
-
- verify(visitor, times(1)).accept(eq(personIcon.getUri()));
- verify(visitor, times(1)).accept(eq(verificationIcon.getUri()));
- verify(visitor, times(1)).accept(eq(answerIntent.getIntent().getData()));
- verify(visitor, times(1)).accept(eq(declineUri));
}
@Test
@@ -6381,74 +6352,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testVisitUris_wearableExtender() {
Icon actionIcon = Icon.createWithContentUri("content://media/action");
Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
- Uri displayIntentUri = Uri.parse("content://intent/display");
- PendingIntent displayIntent = getPendingIntentWithUri(displayIntentUri);
- Uri actionIntentUri = Uri.parse("content://intent/action");
- PendingIntent actionIntent = getPendingIntentWithUri(actionIntentUri);
- Uri wearActionIntentUri = Uri.parse("content://intent/wear");
- PendingIntent wearActionIntent = getPendingIntentWithUri(wearActionIntentUri);
+ PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
Notification n = new Notification.Builder(mContext, "a")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
- .addAction(
- new Notification.Action.Builder(actionIcon, "Hey!", actionIntent).build())
- .extend(new Notification.WearableExtender()
- .setDisplayIntent(displayIntent)
- .addAction(new Notification.Action.Builder(wearActionIcon, "Wear!",
- wearActionIntent)
- .build()))
+ .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build())
+ .extend(new Notification.WearableExtender().addAction(
+ new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build()))
.build();
Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
n.visitUris(visitor);
verify(visitor).accept(eq(actionIcon.getUri()));
- verify(visitor, times(1)).accept(eq(actionIntentUri));
verify(visitor).accept(eq(wearActionIcon.getUri()));
- verify(visitor, times(1)).accept(eq(wearActionIntentUri));
- }
-
- @Test
- public void testVisitUris_tvExtender() {
- Uri contentIntentUri = Uri.parse("content://intent/content");
- PendingIntent contentIntent = getPendingIntentWithUri(contentIntentUri);
- Uri deleteIntentUri = Uri.parse("content://intent/delete");
- PendingIntent deleteIntent = getPendingIntentWithUri(deleteIntentUri);
- Notification n = new Notification.Builder(mContext, "a")
- .extend(
- new Notification.TvExtender()
- .setContentIntent(contentIntent)
- .setDeleteIntent(deleteIntent))
- .build();
-
- Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
- n.visitUris(visitor);
-
- verify(visitor, times(1)).accept(eq(contentIntentUri));
- verify(visitor, times(1)).accept(eq(deleteIntentUri));
- }
-
- @Test
- public void testVisitUris_carExtender() {
- final String testParticipant = "testParticipant";
- Uri readPendingIntentUri = Uri.parse("content://intent/read");
- PendingIntent readPendingIntent = getPendingIntentWithUri(readPendingIntentUri);
- Uri replyPendingIntentUri = Uri.parse("content://intent/reply");
- PendingIntent replyPendingIntent = getPendingIntentWithUri(replyPendingIntentUri);
- final RemoteInput testRemoteInput = new RemoteInput.Builder("key").build();
-
- Notification n = new Notification.Builder(mContext, "a")
- .extend(new Notification.CarExtender().setUnreadConversation(
- new Notification.CarExtender.Builder(testParticipant)
- .setReadPendingIntent(readPendingIntent)
- .setReplyAction(replyPendingIntent, testRemoteInput)
- .build()))
- .build();
-
- Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
- n.visitUris(visitor);
-
- verify(visitor, times(1)).accept(eq(readPendingIntentUri));
- verify(visitor, times(1)).accept(eq(replyPendingIntentUri));
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
index ea948ca0e28b..44dbe385a144 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
@@ -146,10 +146,6 @@ public class NotificationVisitUrisTest extends UiServiceTestCase {
.put(Notification.Action.Builder.class, "extend")
// Overwrites icon supplied to constructor.
.put(Notification.BubbleMetadata.Builder.class, "setIcon")
- // Overwrites intent supplied to constructor.
- .put(Notification.BubbleMetadata.Builder.class, "setIntent")
- // Overwrites intent supplied to constructor.
- .put(Notification.BubbleMetadata.Builder.class, "setDeleteIntent")
// Discards previously-added actions.
.put(RemoteViews.class, "mergeRemoteViews")
.build();
@@ -684,14 +680,14 @@ public class NotificationVisitUrisTest extends UiServiceTestCase {
}
if (clazz == Intent.class) {
- return new Intent("action", generateUri(where.plus(Intent.class)));
+ // TODO(b/281044385): Are Intent Uris (new Intent(String,Uri)) relevant?
+ return new Intent("action");
}
if (clazz == PendingIntent.class) {
- // PendingIntent can have an Intent with a Uri.
- Uri intentUri = generateUri(where.plus(PendingIntent.class));
- return PendingIntent.getActivity(mContext, 0,
- new Intent("action", intentUri),
+ // PendingIntent can have an Intent with a Uri but those are inaccessible and
+ // not inspected.
+ return PendingIntent.getActivity(mContext, 0, new Intent("action"),
PendingIntent.FLAG_IMMUTABLE);
}
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/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
new file mode 100644
index 000000000000..49efd1bdd92a
--- /dev/null
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.RemoteException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class VibratorControlServiceTest {
+
+ private VibratorControlService mVibratorControlService;
+ private final Object mLock = new Object();
+
+ @Before
+ public void setUp() throws Exception {
+ mVibratorControlService = new VibratorControlService(new VibratorControllerHolder(), mLock);
+ }
+
+ @Test
+ public void testRegisterVibratorController() throws RemoteException {
+ FakeVibratorController fakeController = new FakeVibratorController();
+ mVibratorControlService.registerVibratorController(fakeController);
+
+ assertThat(fakeController.isLinkedToDeath).isTrue();
+ }
+
+ @Test
+ public void testUnregisterVibratorController_providingTheRegisteredController_performsRequest()
+ throws RemoteException {
+ FakeVibratorController fakeController = new FakeVibratorController();
+ mVibratorControlService.registerVibratorController(fakeController);
+ mVibratorControlService.unregisterVibratorController(fakeController);
+ assertThat(fakeController.isLinkedToDeath).isFalse();
+ }
+
+ @Test
+ public void testUnregisterVibratorController_providingAnInvalidController_ignoresRequest()
+ throws RemoteException {
+ FakeVibratorController fakeController1 = new FakeVibratorController();
+ FakeVibratorController fakeController2 = new FakeVibratorController();
+ mVibratorControlService.registerVibratorController(fakeController1);
+
+ mVibratorControlService.unregisterVibratorController(fakeController2);
+ assertThat(fakeController1.isLinkedToDeath).isTrue();
+ }
+}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
new file mode 100644
index 000000000000..79abe21a301d
--- /dev/null
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.RemoteException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class VibratorControllerHolderTest {
+
+ private final FakeVibratorController mFakeVibratorController = new FakeVibratorController();
+ private VibratorControllerHolder mVibratorControllerHolder;
+
+ @Before
+ public void setUp() throws Exception {
+ mVibratorControllerHolder = new VibratorControllerHolder();
+ }
+
+ @Test
+ public void testSetVibratorController_linksVibratorControllerToDeath() throws RemoteException {
+ mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
+ assertThat(mVibratorControllerHolder.getVibratorController())
+ .isEqualTo(mFakeVibratorController);
+ assertThat(mFakeVibratorController.isLinkedToDeath).isTrue();
+ }
+
+ @Test
+ public void testSetVibratorController_setControllerToNull_unlinksVibratorControllerToDeath()
+ throws RemoteException {
+ mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
+ mVibratorControllerHolder.setVibratorController(null);
+ assertThat(mFakeVibratorController.isLinkedToDeath).isFalse();
+ assertThat(mVibratorControllerHolder.getVibratorController()).isNull();
+ }
+
+ @Test
+ public void testBinderDied_withValidController_unlinksVibratorControllerToDeath()
+ throws RemoteException {
+ mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
+ mVibratorControllerHolder.binderDied(mFakeVibratorController);
+ assertThat(mFakeVibratorController.isLinkedToDeath).isFalse();
+ assertThat(mVibratorControllerHolder.getVibratorController()).isNull();
+ }
+
+ @Test
+ public void testBinderDied_withInvalidController_ignoresRequest()
+ throws RemoteException {
+ mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
+ FakeVibratorController imposterVibratorController = new FakeVibratorController();
+ mVibratorControllerHolder.binderDied(imposterVibratorController);
+ assertThat(mFakeVibratorController.isLinkedToDeath).isTrue();
+ assertThat(mVibratorControllerHolder.getVibratorController())
+ .isEqualTo(mFakeVibratorController);
+ }
+}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 4e9bbe0a28fe..d6b2116e2682 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -307,9 +307,10 @@ public class VibratorManagerServiceTest {
@Override
void addService(String name, IBinder service) {
- Object serviceInstance = service;
- mExternalVibratorService =
- (VibratorManagerService.ExternalVibratorService) serviceInstance;
+ if (service instanceof VibratorManagerService.ExternalVibratorService) {
+ mExternalVibratorService =
+ (VibratorManagerService.ExternalVibratorService) service;
+ }
}
HapticFeedbackVibrationProvider createHapticFeedbackVibrationProvider(
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
new file mode 100644
index 000000000000..7e235870cedc
--- /dev/null
+++ b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.annotation.NonNull;
+import android.frameworks.vibrator.IVibratorController;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * Provides a fake implementation of {@link android.frameworks.vibrator.IVibratorController} for
+ * testing.
+ */
+public final class FakeVibratorController extends IVibratorController.Stub {
+
+ public boolean isLinkedToDeath = false;
+
+ @Override
+ public void requestVibrationParams(int i, long l, IBinder iBinder) throws RemoteException {
+
+ }
+
+ @Override
+ public int getInterfaceVersion() throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public String getInterfaceHash() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
+ super.linkToDeath(recipient, flags);
+ isLinkedToDeath = true;
+ }
+
+ @Override
+ public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {
+ isLinkedToDeath = false;
+ return super.unlinkToDeath(recipient, flags);
+ }
+}
diff --git a/services/tests/voiceinteractiontests/Android.bp b/services/tests/voiceinteractiontests/Android.bp
index 744cb63f72b3..8a79fe443179 100644
--- a/services/tests/voiceinteractiontests/Android.bp
+++ b/services/tests/voiceinteractiontests/Android.bp
@@ -44,6 +44,7 @@ android_test {
"servicestests-core-utils",
"servicestests-utils-mockito-extended",
"truth",
+ "frameworks-base-testutils",
],
libs: [
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java b/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java
new file mode 100644
index 000000000000..159c760992c6
--- /dev/null
+++ b/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.voiceinteraction;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.Manifest;
+import android.app.ActivityManagerInternal;
+import android.app.AppOpsManager;
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.PermissionEnforcer;
+import android.os.Process;
+import android.os.test.FakePermissionEnforcer;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.modules.utils.testing.ExtendedMockitoRule;
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.quality.Strictness;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class SetSandboxedTrainingDataAllowedTest {
+
+ @Captor private ArgumentCaptor<Integer> mOpIdCaptor, mUidCaptor, mOpModeCaptor;
+
+ @Mock
+ private AppOpsManager mAppOpsManager;
+
+ @Mock
+ private VoiceInteractionManagerServiceImpl mVoiceInteractionManagerServiceImpl;
+
+ private FakePermissionEnforcer mPermissionEnforcer = new FakePermissionEnforcer();
+
+ private Context mContext;
+
+ private VoiceInteractionManagerService mVoiceInteractionManagerService;
+ private VoiceInteractionManagerService.VoiceInteractionManagerServiceStub
+ mVoiceInteractionManagerServiceStub;
+
+ private ApplicationInfo mApplicationInfo = new ApplicationInfo();
+
+ @Rule
+ public final ExtendedMockitoRule mExtendedMockitoRule =
+ new ExtendedMockitoRule.Builder(this)
+ .setStrictness(Strictness.WARN)
+ .mockStatic(LocalServices.class)
+ .mockStatic(PermissionEnforcer.class)
+ .build();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(ApplicationProvider.getApplicationContext());
+
+ doReturn(mPermissionEnforcer).when(() -> PermissionEnforcer.fromContext(any()));
+ doReturn(mock(PermissionManagerServiceInternal.class)).when(
+ () -> LocalServices.getService(PermissionManagerServiceInternal.class));
+ doReturn(mock(ActivityManagerInternal.class)).when(
+ () -> LocalServices.getService(ActivityManagerInternal.class));
+ doReturn(mock(UserManagerInternal.class)).when(
+ () -> LocalServices.getService(UserManagerInternal.class));
+ doReturn(mock(ActivityTaskManagerInternal.class)).when(
+ () -> LocalServices.getService(ActivityTaskManagerInternal.class));
+ doReturn(mock(LegacyPermissionManagerInternal.class)).when(
+ () -> LocalServices.getService(LegacyPermissionManagerInternal.class));
+ doReturn(mock(RoleManager.class)).when(mContext).getSystemService(RoleManager.class);
+ doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE);
+ doReturn(mApplicationInfo).when(mVoiceInteractionManagerServiceImpl).getApplicationInfo();
+
+ mVoiceInteractionManagerService = new VoiceInteractionManagerService(mContext);
+ mVoiceInteractionManagerServiceStub =
+ mVoiceInteractionManagerService.new VoiceInteractionManagerServiceStub();
+ mVoiceInteractionManagerServiceStub.mImpl = mVoiceInteractionManagerServiceImpl;
+ mPermissionEnforcer.grant(Manifest.permission.MANAGE_HOTWORD_DETECTION);
+ }
+
+ @Test
+ 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.setShouldReceiveSandboxedTrainingData(
+ /* allowed= */ true);
+
+ verify(mAppOpsManager).setUidMode(mOpIdCaptor.capture(), mUidCaptor.capture(),
+ mOpModeCaptor.capture());
+ assertThat(mOpIdCaptor.getValue()).isEqualTo(
+ AppOpsManager.OP_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA);
+ assertThat(mOpModeCaptor.getValue()).isEqualTo(AppOpsManager.MODE_ALLOWED);
+ assertThat(mUidCaptor.getValue()).isEqualTo(Process.myUid());
+ }
+
+ @Test
+ 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;
+
+ // Simulate missing MANAGE_HOTWORD_DETECTION permission.
+ mPermissionEnforcer.revoke(Manifest.permission.MANAGE_HOTWORD_DETECTION);
+
+ assertThrows(SecurityException.class,
+ () -> mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
+ /* allowed= */ true));
+
+ verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ 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.setShouldReceiveSandboxedTrainingData(
+ /* allowed= */ true));
+
+ verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ 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.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/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/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 71d2504e1746..dfe79bf1e3e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -993,7 +993,9 @@ public class DisplayContentTests extends WindowTestsBase {
dc.getDisplayPolicy().getDecorInsetsInfo(ROTATION_0, dc.mBaseDisplayHeight,
dc.mBaseDisplayWidth).mConfigFrame.set(0, 0, 1000, 990);
dc.computeScreenConfiguration(config, ROTATION_0);
+ dc.onRequestedOverrideConfigurationChanged(config);
assertEquals(Configuration.ORIENTATION_LANDSCAPE, config.orientation);
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getNaturalOrientation());
}
@Test
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/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 3d2340cca378..72db7fecb8ac 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2278,6 +2278,12 @@ public class UsageStatsService extends SystemService implements
"Only the system or holders of the REPORT_USAGE_STATS"
+ " permission are allowed to call reportUserInteraction");
}
+ if (userId != UserHandle.getCallingUserId()) {
+ // Cross-user event reporting.
+ getContext().enforceCallingPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "Caller doesn't have INTERACT_ACROSS_USERS_FULL permission");
+ }
} else {
if (!isCallingUidSystem()) {
throw new SecurityException("Only system is allowed to call"
@@ -2287,7 +2293,8 @@ public class UsageStatsService extends SystemService implements
// Verify if this package exists before reporting an event for it.
if (mPackageManagerInternal.getPackageUid(packageName, 0, userId) < 0) {
- throw new IllegalArgumentException("Package " + packageName + "not exist!");
+ throw new IllegalArgumentException("Package " + packageName
+ + " does not exist!");
}
final Event event = new Event(USER_INTERACTION, SystemClock.elapsedRealtime());
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index b214591610de..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");
}
@@ -2273,9 +2273,9 @@ public class VoiceInteractionManagerService extends SystemService {
private boolean isCallerPreinstalledAssistant() {
return mImpl != null
- && mImpl.mInfo.getServiceInfo().applicationInfo.uid == Binder.getCallingUid()
- && (mImpl.mInfo.getServiceInfo().applicationInfo.isSystemApp()
- || mImpl.mInfo.getServiceInfo().applicationInfo.isUpdatedSystemApp());
+ && mImpl.getApplicationInfo().uid == Binder.getCallingUid()
+ && (mImpl.getApplicationInfo().isSystemApp()
+ || mImpl.getApplicationInfo().isUpdatedSystemApp());
}
private void setImplLocked(VoiceInteractionManagerServiceImpl impl) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 3c4b58fa2b69..7e0cbad1e828 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -40,6 +40,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
@@ -540,6 +541,10 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
return mInfo.getSupportsLocalInteraction();
}
+ public ApplicationInfo getApplicationInfo() {
+ return mInfo.getServiceInfo().applicationInfo;
+ }
+
public void startListeningVisibleActivityChangedLocked(@NonNull IBinder token) {
if (DEBUG) {
Slog.d(TAG, "startListeningVisibleActivityChangedLocked: token=" + token);
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/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index b356fde53417..326b6f5af613 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1508,8 +1508,14 @@ public class SubscriptionManager {
public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
if (listener == null) return;
- addOnSubscriptionsChangedListener(
- new HandlerExecutor(new Handler(listener.getCreatorLooper())), listener);
+ Looper looper = listener.getCreatorLooper();
+ if (looper == null) {
+ throw new RuntimeException(
+ "Can't create handler inside thread " + Thread.currentThread()
+ + " that has not called Looper.prepare()");
+ }
+
+ addOnSubscriptionsChangedListener(new HandlerExecutor(new Handler(looper)), listener);
}
/**
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..397fb2d6db96 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.
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/LongArrayMultiStateCounter_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java
index 068dfe8f3d11..a1356237e5a4 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java
@@ -100,6 +100,10 @@ public class LongArrayMultiStateCounter_host {
mLastStateChangeTimestampMs = timestampMs;
}
+ public void setValue(int state, long[] values) {
+ System.arraycopy(values, 0, mStates[state].mCounter, 0, mArrayLength);
+ }
+
public void updateValue(long[] values, long timestampMs) {
if (mEnabled || mLastUpdateTimestampMs < mLastStateChangeTimestampMs) {
if (timestampMs < mLastStateChangeTimestampMs) {
@@ -306,6 +310,11 @@ public class LongArrayMultiStateCounter_host {
return getInstance(instanceId).mArrayLength;
}
+ public static void native_setValues(long instanceId, int state, long containerInstanceId) {
+ getInstance(instanceId).setValue(state,
+ LongArrayContainer_host.getInstance(containerInstanceId));
+ }
+
public static void native_updateValues(long instanceId, long containerInstanceId,
long timestampMs) {
getInstance(instanceId).updateValue(
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);