summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AconfigFlags.bp21
-rw-r--r--api/javadoc-lint-baseline14
-rw-r--r--cmds/uinput/jni/com_android_commands_uinput_Device.cpp23
-rw-r--r--cmds/uinput/jni/com_android_commands_uinput_Device.h6
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Device.java26
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/EvemuParser.java172
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Event.java29
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java4
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Uinput.java9
-rw-r--r--cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java23
-rw-r--r--core/api/system-current.txt9
-rw-r--r--core/api/test-current.txt5
-rw-r--r--core/java/Android.bp9
-rw-r--r--core/java/android/app/ApplicationPackageManager.java9
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl2
-rw-r--r--core/java/android/app/notification.aconfig17
-rw-r--r--core/java/android/app/time/TEST_MAPPING18
-rw-r--r--core/java/android/app/timedetector/TEST_MAPPING18
-rw-r--r--core/java/android/app/timezonedetector/TEST_MAPPING18
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageManager.java15
-rw-r--r--core/java/android/content/pm/UserProperties.java207
-rw-r--r--core/java/android/content/pm/multiuser.aconfig7
-rw-r--r--core/java/android/os/IUserManager.aidl1
-rw-r--r--core/java/android/os/UserManager.java38
-rw-r--r--core/java/android/service/chooser/flags.aconfig9
-rw-r--r--core/java/android/view/InputDevice.java31
-rw-r--r--core/java/android/view/contentcapture/MainContentCaptureSession.java19
-rw-r--r--core/java/android/webkit/WebViewDelegate.java5
-rw-r--r--core/java/android/webkit/WebViewZygote.java16
-rw-r--r--core/java/android/window/WindowInfosListenerForTest.java41
-rw-r--r--core/java/android/window/flags/window_surfaces.aconfig8
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig7
-rw-r--r--core/java/com/android/internal/pm/parsing/pkg/AndroidPackageHidden.java (renamed from services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageHidden.java)10
-rw-r--r--core/java/com/android/internal/pm/parsing/pkg/AndroidPackageInternal.java (renamed from services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java)2
-rw-r--r--core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java (renamed from services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java)2
-rw-r--r--core/java/com/android/internal/pm/pkg/AndroidPackageSplitImpl.java (renamed from services/core/java/com/android/server/pm/pkg/AndroidPackageSplitImpl.java)8
-rw-r--r--core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java (renamed from services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java)4
-rw-r--r--core/java/com/android/internal/pm/pkg/parsing/ParsingPackageHidden.java (renamed from services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageHidden.java)2
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java14
-rw-r--r--core/java/com/android/server/pm/OWNERS4
-rw-r--r--core/java/com/android/server/pm/pkg/AndroidPackage.java (renamed from services/core/java/com/android/server/pm/pkg/AndroidPackage.java)10
-rw-r--r--core/java/com/android/server/pm/pkg/AndroidPackageSplit.java (renamed from services/core/java/com/android/server/pm/pkg/AndroidPackageSplit.java)0
-rw-r--r--core/jni/android_view_InputDevice.cpp5
-rw-r--r--core/res/res/values/strings.xml16
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--core/tests/timetests/TEST_MAPPING3
-rw-r--r--data/etc/services.core.protolog.json12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java79
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DeviceConfig.kt67
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt19
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml11
-rw-r--r--libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/splitscreen/trace_config/trace_config.textproto1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleOverflowTest.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java151
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt26
-rw-r--r--media/java/android/media/AudioManager.java56
-rw-r--r--media/java/android/media/IAudioService.aidl4
-rw-r--r--media/jni/Android.bp5
-rw-r--r--media/jni/audioeffect/Android.bp5
-rw-r--r--mime/java-res/android.mime.types2
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java9
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt3
-rw-r--r--packages/SettingsLib/res/values/strings.xml6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java11
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java16
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig9
-rw-r--r--packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt734
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt711
-rw-r--r--packages/SystemUI/res/anim/instant_fade_out.xml23
-rw-r--r--packages/SystemUI/res/drawable/ksh_key_item_background.xml2
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml5
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml2
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_key_icon_view.xml9
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml24
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml28
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_key_separator_view.xml (renamed from packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml)21
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml28
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml26
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml15
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_view.xml2
-rw-r--r--packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml3
-rw-r--r--packages/SystemUI/res/layout/screen_record_options.xml2
-rw-r--r--packages/SystemUI/res/values/colors.xml5
-rw-r--r--packages/SystemUI/res/values/dimens.xml5
-rw-r--r--packages/SystemUI/res/values/strings.xml75
-rw-r--r--packages/SystemUI/res/values/styles.xml9
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java111
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterButtonViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapper.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/common/ui/ConfigurationStateTest.kt160
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapperTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorKosmos.kt5
-rw-r--r--ravenwood/Android.bp1
-rw-r--r--services/Android.bp1
-rw-r--r--services/companion/java/com/android/server/companion/virtual/OWNERS6
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java32
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java6
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java74
-rw-r--r--services/core/java/com/android/server/audio/HardeningEnforcer.java109
-rw-r--r--services/core/java/com/android/server/display/mode/BaseModeRefreshRateVote.java59
-rw-r--r--services/core/java/com/android/server/display/mode/CombinedVote.java51
-rw-r--r--services/core/java/com/android/server/display/mode/DisableRefreshRateSwitchingVote.java56
-rw-r--r--services/core/java/com/android/server/display/mode/DisplayModeDirector.java54
-rw-r--r--services/core/java/com/android/server/display/mode/RefreshRateVote.java120
-rw-r--r--services/core/java/com/android/server/display/mode/SizeVote.java88
-rw-r--r--services/core/java/com/android/server/display/mode/SupportedModesVote.java92
-rw-r--r--services/core/java/com/android/server/display/mode/Vote.java194
-rw-r--r--services/core/java/com/android/server/display/mode/VotesStorage.java14
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java13
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java49
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java90
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/InstallRequest.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java16
-rw-r--r--services/core/java/com/android/server/pm/PackageSessionVerifier.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java4
-rw-r--r--services/core/java/com/android/server/pm/ParallelPackageParser.java2
-rw-r--r--services/core/java/com/android/server/pm/ReconcilePackageUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/ScanRequest.java2
-rw-r--r--services/core/java/com/android/server/pm/SharedLibrariesImpl.java2
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java13
-rw-r--r--services/core/java/com/android/server/pm/UserTypeDetails.java42
-rw-r--r--services/core/java/com/android/server/pm/UserTypeFactory.java29
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageCacher.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageParser2.java4
-rw-r--r--services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdater.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java4
-rw-r--r--services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java3
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java9
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageStateInternal.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java3
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java1
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java3
-rw-r--r--services/core/java/com/android/server/webkit/SystemImpl.java22
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateService.java34
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java128
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand2.java91
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java7
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java30
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java19
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java3
-rw-r--r--services/permission/OWNERS4
-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.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.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.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ParallelPackageParserTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanRequestBuilder.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt5
-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.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.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/verify/domain/DomainVerificationCollectorTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt3
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt3
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt3
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/BaseModeRefreshRateVoteTest.kt70
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/CombinedVoteTest.kt57
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/DisableRefreshRateSwitchingVoteTest.kt63
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java261
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/PhysicalVoteTest.kt99
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/RenderVoteTest.kt100
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SizeVoteTest.kt173
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java30
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SupportedModesVoteTest.kt73
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerTest.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/DexMetadataHelperTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java24
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java9
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java2
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java272
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java25
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java1
-rw-r--r--tests/Input/src/com/android/test/input/InputDeviceTest.java2
286 files changed, 4963 insertions, 2497 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 16389b3bcc3c..c80f2eace19a 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -26,6 +26,7 @@ aconfig_srcjars = [
":android.os.flags-aconfig-java{.generated_srcjars}",
":android.os.vibrator.flags-aconfig-java{.generated_srcjars}",
":android.security.flags-aconfig-java{.generated_srcjars}",
+ ":android.service.chooser.flags-aconfig-java{.generated_srcjars}",
":android.service.notification.flags-aconfig-java{.generated_srcjars}",
":android.view.flags-aconfig-java{.generated_srcjars}",
":android.view.accessibility.flags-aconfig-java{.generated_srcjars}",
@@ -683,6 +684,19 @@ cc_aconfig_library {
aconfig_declarations: "device_policy_aconfig_flags",
}
+// Chooser / "Sharesheet"
+aconfig_declarations {
+ name: "android.service.chooser.flags-aconfig",
+ package: "android.service.chooser",
+ srcs: ["core/java/android/service/chooser/flags.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.service.chooser.flags-aconfig-java",
+ aconfig_declarations: "android.service.chooser.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// JobScheduler
aconfig_declarations {
name: "framework-jobscheduler-job.flags-aconfig",
@@ -755,6 +769,13 @@ java_aconfig_library {
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+java_aconfig_library {
+ name: "android.hardware.usb.flags-aconfig-java-host",
+ aconfig_declarations: "android.hardware.usb.flags-aconfig",
+ host_supported: true,
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// WindowingTools
aconfig_declarations {
name: "android.tracing.flags-aconfig",
diff --git a/api/javadoc-lint-baseline b/api/javadoc-lint-baseline
index a4174ee6ae17..79927020d5ea 100644
--- a/api/javadoc-lint-baseline
+++ b/api/javadoc-lint-baseline
@@ -1,17 +1,3 @@
-// b/303477132
-android/app/appsearch/AppSearchSchema.java:402: lint: Unresolved link/see tag "#getIndexableNestedProperties()" in android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder [101]
-android/app/appsearch/AppSearchSession.java:55: lint: Unresolved link/see tag "Features#LIST_FILTER_QUERY_LANGUAGE" in android.app.appsearch.AppSearchSession [101]
-android/app/appsearch/AppSearchSession.java:55: lint: Unresolved link/see tag "Features#NUMERIC_SEARCH" in android.app.appsearch.AppSearchSession [101]
-android/app/appsearch/AppSearchSession.java:55: lint: Unresolved link/see tag "Features#VERBATIM_SEARCH" in android.app.appsearch.AppSearchSession [101]
-android/app/appsearch/AppSearchSession.java:55: lint: Unresolved link/see tag "Features#isFeatureSupported" in android.app.appsearch.AppSearchSession [101]
-android/app/appsearch/JoinSpec.java:219: lint: Unresolved link/see tag "android.app.appsearch.SearchSpec.RankingStrategy#RANKING_STRATEGY_JOIN_AGGREGATE_SCORE SearchSpec.RankingStrategy#RANKING_STRATEGY_JOIN_AGGREGATE_SCORE" in android.app.appsearch.JoinSpec.Builder [101]
-android/app/appsearch/SearchSpec.java:230: lint: Unresolved link/see tag "Features#NUMERIC_SEARCH" in android.app.appsearch.SearchSpec [101]
-android/app/appsearch/SearchSpec.java:237: lint: Unresolved link/see tag "Features#VERBATIM_SEARCH" in android.app.appsearch.SearchSpec [101]
-android/app/appsearch/SearchSpec.java:244: lint: Unresolved link/see tag "Features#LIST_FILTER_QUERY_LANGUAGE" in android.app.appsearch.SearchSpec [101]
-android/app/appsearch/SearchSpec.java:913: lint: Unresolved link/see tag "Features#NUMERIC_SEARCH" in android.app.appsearch.SearchSpec.Builder [101]
-android/app/appsearch/SearchSpec.java:925: lint: Unresolved link/see tag "Features#VERBATIM_SEARCH" in android.app.appsearch.SearchSpec.Builder [101]
-android/app/appsearch/SearchSpec.java:929: lint: Unresolved link/see tag "Features#LIST_FILTER_QUERY_LANGUAGE" in android.app.appsearch.SearchSpec.Builder [101]
-
// b/303582215
android/hardware/camera2/CameraCharacteristics.java:2169: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101]
android/hardware/camera2/CameraCharacteristics.java:2344: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#concurrent-stream-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101]
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
index ec2b1f4db521..a78a46504684 100644
--- a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
@@ -96,9 +96,9 @@ JNIEnv* DeviceCallback::getJNIEnv() {
return env;
}
-std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, int32_t vid,
- int32_t pid, uint16_t bus, uint32_t ffEffectsMax,
- const char* port,
+std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, int32_t vendorId,
+ int32_t productId, int32_t versionId, uint16_t bus,
+ uint32_t ffEffectsMax, const char* port,
std::unique_ptr<DeviceCallback> callback) {
android::base::unique_fd fd(::open(UINPUT_PATH, O_RDWR | O_NONBLOCK | O_CLOEXEC));
if (!fd.ok()) {
@@ -118,8 +118,9 @@ std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, i
strlcpy(setupDescriptor.name, name, UINPUT_MAX_NAME_SIZE);
setupDescriptor.id.version = 1;
setupDescriptor.id.bustype = bus;
- setupDescriptor.id.vendor = vid;
- setupDescriptor.id.product = pid;
+ setupDescriptor.id.vendor = vendorId;
+ setupDescriptor.id.product = productId;
+ setupDescriptor.id.version = versionId;
setupDescriptor.ff_effects_max = ffEffectsMax;
// Request device configuration.
@@ -242,9 +243,9 @@ std::vector<int32_t> toVector(JNIEnv* env, jintArray javaArray) {
return data;
}
-static jlong openUinputDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid,
- jint pid, jint bus, jint ffEffectsMax, jstring rawPort,
- jobject callback) {
+static jlong openUinputDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id,
+ jint vendorId, jint productId, jint versionId, jint bus,
+ jint ffEffectsMax, jstring rawPort, jobject callback) {
ScopedUtfChars name(env, rawName);
if (name.c_str() == nullptr) {
return 0;
@@ -255,8 +256,8 @@ static jlong openUinputDevice(JNIEnv* env, jclass /* clazz */, jstring rawName,
std::make_unique<uinput::DeviceCallback>(env, callback);
std::unique_ptr<uinput::UinputDevice> d =
- uinput::UinputDevice::open(id, name.c_str(), vid, pid, bus, ffEffectsMax, port.c_str(),
- std::move(cb));
+ uinput::UinputDevice::open(id, name.c_str(), vendorId, productId, versionId, bus,
+ ffEffectsMax, port.c_str(), std::move(cb));
return reinterpret_cast<jlong>(d.release());
}
@@ -326,7 +327,7 @@ static jint getEvdevInputPropByLabel(JNIEnv* env, jclass /* clazz */, jstring ra
static JNINativeMethod sMethods[] = {
{"nativeOpenUinputDevice",
- "(Ljava/lang/String;IIIIILjava/lang/String;"
+ "(Ljava/lang/String;IIIIIILjava/lang/String;"
"Lcom/android/commands/uinput/Device$DeviceCallback;)J",
reinterpret_cast<void*>(openUinputDevice)},
{"nativeInjectEvent", "(JIII)V", reinterpret_cast<void*>(injectEvent)},
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.h b/cmds/uinput/jni/com_android_commands_uinput_Device.h
index 6da3d7968ed0..9769a75bd9ef 100644
--- a/cmds/uinput/jni/com_android_commands_uinput_Device.h
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.h
@@ -46,9 +46,9 @@ private:
class UinputDevice {
public:
- static std::unique_ptr<UinputDevice> open(int32_t id, const char* name, int32_t vid,
- int32_t pid, uint16_t bus, uint32_t ff_effects_max,
- const char* port,
+ static std::unique_ptr<UinputDevice> open(int32_t id, const char* name, int32_t vendorId,
+ int32_t productId, int32_t versionId, uint16_t bus,
+ uint32_t ff_effects_max, const char* port,
std::unique_ptr<DeviceCallback> callback);
virtual ~UinputDevice();
diff --git a/cmds/uinput/src/com/android/commands/uinput/Device.java b/cmds/uinput/src/com/android/commands/uinput/Device.java
index b0fa34c68092..787055c8cd89 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Device.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Device.java
@@ -61,8 +61,9 @@ public class Device {
System.loadLibrary("uinputcommand_jni");
}
- private static native long nativeOpenUinputDevice(String name, int id, int vid, int pid,
- int bus, int ffEffectsMax, String port, DeviceCallback callback);
+ private static native long nativeOpenUinputDevice(String name, int id, int vendorId,
+ int productId, int versionId, int bus, int ffEffectsMax, String port,
+ DeviceCallback callback);
private static native void nativeCloseUinputDevice(long ptr);
private static native void nativeInjectEvent(long ptr, int type, int code, int value);
private static native void nativeConfigure(int handle, int code, int[] configs);
@@ -71,7 +72,7 @@ public class Device {
private static native int nativeGetEvdevEventCodeByLabel(int type, String label);
private static native int nativeGetEvdevInputPropByLabel(String label);
- public Device(int id, String name, int vid, int pid, int bus,
+ public Device(int id, String name, int vendorId, int productId, int versionId, int bus,
SparseArray<int[]> configuration, int ffEffectsMax,
SparseArray<InputAbsInfo> absInfo, String port) {
mId = id;
@@ -83,19 +84,20 @@ public class Device {
mOutputStream = System.out;
SomeArgs args = SomeArgs.obtain();
args.argi1 = id;
- args.argi2 = vid;
- args.argi3 = pid;
- args.argi4 = bus;
- args.argi5 = ffEffectsMax;
+ args.argi2 = vendorId;
+ args.argi3 = productId;
+ args.argi4 = versionId;
+ args.argi5 = bus;
+ args.argi6 = ffEffectsMax;
if (name != null) {
args.arg1 = name;
} else {
- args.arg1 = id + ":" + vid + ":" + pid;
+ args.arg1 = id + ":" + vendorId + ":" + productId;
}
if (port != null) {
args.arg2 = port;
} else {
- args.arg2 = "uinput:" + id + ":" + vid + ":" + pid;
+ args.arg2 = "uinput:" + id + ":" + vendorId + ":" + productId;
}
mHandler.obtainMessage(MSG_OPEN_UINPUT_DEVICE, args).sendToTarget();
@@ -161,8 +163,10 @@ public class Device {
case MSG_OPEN_UINPUT_DEVICE:
SomeArgs args = (SomeArgs) msg.obj;
String name = (String) args.arg1;
- mPtr = nativeOpenUinputDevice(name, args.argi1, args.argi2,
- args.argi3, args.argi4, args.argi5, (String) args.arg2,
+ mPtr = nativeOpenUinputDevice(name, args.argi1 /* id */,
+ args.argi2 /* vendorId */, args.argi3 /* productId */,
+ args.argi4 /* versionId */, args.argi5 /* bus */,
+ args.argi6 /* ffEffectsMax */, (String) args.arg2 /* port */,
new DeviceCallback());
if (mPtr == 0) {
RuntimeException ex = new RuntimeException(
diff --git a/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java b/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java
index b89e2cdbd905..7652f2403f6e 100644
--- a/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java
+++ b/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java
@@ -19,8 +19,8 @@ package com.android.commands.uinput;
import android.annotation.Nullable;
import android.util.SparseArray;
-import java.io.BufferedReader;
import java.io.IOException;
+import java.io.LineNumberReader;
import java.io.Reader;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -47,10 +47,11 @@ public class EvemuParser implements EventParser {
private static final int REGISTRATION_DELAY_MILLIS = 500;
private static class CommentAwareReader {
- private final BufferedReader mReader;
+ private final LineNumberReader mReader;
+ private String mPreviousLine;
private String mNextLine;
- CommentAwareReader(BufferedReader in) throws IOException {
+ CommentAwareReader(LineNumberReader in) throws IOException {
mReader = in;
mNextLine = findNextLine();
}
@@ -90,12 +91,46 @@ public class EvemuParser implements EventParser {
/** Moves to the next line of the file. */
public void advance() throws IOException {
+ mPreviousLine = mNextLine;
mNextLine = findNextLine();
}
public boolean isAtEndOfFile() {
return mNextLine == null;
}
+
+ /** Returns the previous line, for error messages. */
+ public String getPreviousLine() {
+ return mPreviousLine;
+ }
+
+ /** Returns the number of the <b>previous</b> line. */
+ public int getPreviousLineNumber() {
+ return mReader.getLineNumber() - 1;
+ }
+ }
+
+ public static class ParsingException extends RuntimeException {
+ private final int mLineNumber;
+ private final String mLine;
+
+ ParsingException(String message, CommentAwareReader reader) {
+ this(message, reader.getPreviousLine(), reader.getPreviousLineNumber());
+ }
+
+ ParsingException(String message, String line, int lineNumber) {
+ super(message);
+ mLineNumber = lineNumber;
+ mLine = line;
+ }
+
+ /** Returns a nicely formatted error message, including the line number and line. */
+ public String makeErrorMessage() {
+ return String.format("""
+ Parsing error on line %d: %s
+ --> %s
+ """, mLineNumber, getMessage(), mLine);
+ }
}
private final CommentAwareReader mReader;
@@ -107,7 +142,7 @@ public class EvemuParser implements EventParser {
private final Queue<Event> mQueuedEvents = new ArrayDeque<>(2);
public EvemuParser(Reader in) throws IOException {
- mReader = new CommentAwareReader(new BufferedReader(in));
+ mReader = new CommentAwareReader(new LineNumberReader(in));
mQueuedEvents.add(parseRegistrationEvent());
// The kernel takes a little time to set up an evdev device after the initial
@@ -133,20 +168,22 @@ public class EvemuParser implements EventParser {
return null;
}
- final String[] parts = expectLineWithParts("E", 4);
+ final String line = expectLine("E");
+ final String[] parts = expectParts(line, 4);
final String[] timeParts = parts[0].split("\\.");
if (timeParts.length != 2) {
- throw new RuntimeException("Invalid timestamp (does not contain a '.')");
+ throw new ParsingException(
+ "Invalid timestamp '" + parts[0] + "' (should contain a single '.')", mReader);
}
// TODO(b/310958309): use timeMicros to set the timestamp on the event being sent.
final long timeMicros =
- Long.parseLong(timeParts[0]) * 1_000_000 + Integer.parseInt(timeParts[1]);
+ parseLong(timeParts[0], 10) * 1_000_000 + parseInt(timeParts[1], 10);
final Event.Builder eb = new Event.Builder();
eb.setId(DEVICE_ID);
eb.setCommand(Event.Command.INJECT);
- final int eventType = Integer.parseInt(parts[1], 16);
- final int eventCode = Integer.parseInt(parts[2], 16);
- final int value = Integer.parseInt(parts[3]);
+ final int eventType = parseInt(parts[1], 16);
+ final int eventCode = parseInt(parts[2], 16);
+ final int value = parseInt(parts[3], 10);
eb.setInjections(new int[] {eventType, eventCode, value});
if (mLastEventTimeMicros == -1) {
@@ -184,11 +221,12 @@ public class EvemuParser implements EventParser {
eb.setCommand(Event.Command.REGISTER);
eb.setName(expectLine("N"));
- final String[] idStrings = expectLineWithParts("I", 4);
- eb.setBusId(Integer.parseInt(idStrings[0], 16));
- eb.setVid(Integer.parseInt(idStrings[1], 16));
- eb.setPid(Integer.parseInt(idStrings[2], 16));
- // TODO(b/302297266): support setting the version ID, and set it to idStrings[3].
+ final String idsLine = expectLine("I");
+ final String[] idStrings = expectParts(idsLine, 4);
+ eb.setBusId(parseInt(idStrings[0], 16));
+ eb.setVendorId(parseInt(idStrings[1], 16));
+ eb.setProductId(parseInt(idStrings[2], 16));
+ eb.setVersionId(parseInt(idStrings[3], 16));
final SparseArray<int[]> config = new SparseArray<>();
config.append(Event.UinputControlCode.UI_SET_PROPBIT.getValue(), parseProperties());
@@ -215,33 +253,39 @@ public class EvemuParser implements EventParser {
}
private int[] parseProperties() throws IOException {
- final List<String> propBitmapParts = new ArrayList<>();
+ final ArrayList<Integer> propBitmapParts = new ArrayList<>();
String line = acceptLine("P");
while (line != null) {
- propBitmapParts.addAll(List.of(line.strip().split(" ")));
+ String[] parts = line.strip().split(" ");
+ propBitmapParts.ensureCapacity(propBitmapParts.size() + parts.length);
+ for (String part : parts) {
+ propBitmapParts.add(parseBitmapPart(part, line));
+ }
line = acceptLine("P");
}
- return hexStringBitmapToEventCodes(propBitmapParts);
+ return bitmapToEventCodes(propBitmapParts);
}
private void parseAxisBitmaps(SparseArray<int[]> config) throws IOException {
- final Map<Integer, List<String>> axisBitmapParts = new HashMap<>();
+ final Map<Integer, ArrayList<Integer>> axisBitmapParts = new HashMap<>();
String line = acceptLine("B");
while (line != null) {
final String[] parts = line.strip().split(" ");
if (parts.length < 2) {
- throw new RuntimeException(
+ throw new ParsingException(
"Expected event type and at least one bitmap byte on 'B:' line; only found "
- + parts.length + " elements");
+ + parts.length + " elements", mReader);
}
- final int eventType = Integer.parseInt(parts[0], 16);
+ final int eventType = parseInt(parts[0], 16);
// EV_SYN cannot be configured through uinput, so skip it.
if (eventType != Event.EV_SYN) {
if (!axisBitmapParts.containsKey(eventType)) {
axisBitmapParts.put(eventType, new ArrayList<>());
}
+ ArrayList<Integer> bitmapParts = axisBitmapParts.get(eventType);
+ bitmapParts.ensureCapacity(bitmapParts.size() + parts.length);
for (int i = 1; i < parts.length; i++) {
- axisBitmapParts.get(eventType).add(parts[i]);
+ axisBitmapParts.get(eventType).add(parseBitmapPart(parts[i], line));
}
}
line = acceptLine("B");
@@ -253,7 +297,7 @@ public class EvemuParser implements EventParser {
}
final Event.UinputControlCode controlCode =
Event.UinputControlCode.forEventType(entry.getKey());
- final int[] eventCodes = hexStringBitmapToEventCodes(entry.getValue());
+ final int[] eventCodes = bitmapToEventCodes(entry.getValue());
if (controlCode != null && eventCodes.length > 0) {
config.append(controlCode.getValue(), eventCodes);
eventTypesToSet.add(entry.getKey());
@@ -263,24 +307,33 @@ public class EvemuParser implements EventParser {
Event.UinputControlCode.UI_SET_EVBIT.getValue(), unboxIntList(eventTypesToSet));
}
+ private int parseBitmapPart(String part, String line) {
+ int b = parseInt(part, 16);
+ if (b < 0x0 || b > 0xff) {
+ throw new ParsingException("Bitmap part '" + part
+ + "' invalid; parts must be hexadecimal values between 00 and ff.", mReader);
+ }
+ return b;
+ }
+
private SparseArray<InputAbsInfo> parseAbsInfos() throws IOException {
final SparseArray<InputAbsInfo> absInfos = new SparseArray<>();
String line = acceptLine("A");
while (line != null) {
final String[] parts = line.strip().split(" ");
if (parts.length < 5 || parts.length > 6) {
- throw new RuntimeException(
- "'A:' lines should have the format 'A: <index (hex)> <min> <max> <fuzz> "
+ throw new ParsingException(
+ "AbsInfo lines should have the format 'A: <index (hex)> <min> <max> <fuzz> "
+ "<flat> [<resolution>]'; expected 5 or 6 numbers but found "
- + parts.length);
+ + parts.length, mReader);
}
- final int axisCode = Integer.parseInt(parts[0], 16);
+ final int axisCode = parseInt(parts[0], 16);
final InputAbsInfo info = new InputAbsInfo();
- info.minimum = Integer.parseInt(parts[1]);
- info.maximum = Integer.parseInt(parts[2]);
- info.fuzz = Integer.parseInt(parts[3]);
- info.flat = Integer.parseInt(parts[4]);
- info.resolution = parts.length > 5 ? Integer.parseInt(parts[5]) : 0;
+ info.minimum = parseInt(parts[1], 10);
+ info.maximum = parseInt(parts[2], 10);
+ info.fuzz = parseInt(parts[3], 10);
+ info.flat = parseInt(parts[4], 10);
+ info.resolution = parts.length > 5 ? parseInt(parts[5], 10) : 0;
absInfos.append(axisCode, info);
line = acceptLine("A");
}
@@ -305,7 +358,9 @@ public class EvemuParser implements EventParser {
private String expectLine(String type) throws IOException {
final String line = acceptLine(type);
if (line == null) {
- throw new RuntimeException("Expected line of type '" + type + "'");
+ throw new ParsingException("Expected line of type '" + type + "'. (Lines should be in "
+ + "the order N, I, P, B, A, L, S, E.)",
+ mReader.peekLine(), mReader.getPreviousLineNumber() + 1);
} else {
return line;
}
@@ -325,9 +380,8 @@ public class EvemuParser implements EventParser {
}
final String[] lineParts = line.split(": ", 2);
if (lineParts.length < 2) {
- // TODO(b/302297266): make a proper exception class for syntax errors, including line
- // numbers, etc.. (We can use LineNumberReader to track them.)
- throw new RuntimeException("Line without ': '");
+ throw new ParsingException("Missing type separator ': '",
+ line, mReader.getPreviousLineNumber() + 1);
}
if (lineParts[0].equals(type)) {
mReader.advance();
@@ -337,31 +391,37 @@ public class EvemuParser implements EventParser {
}
}
- /**
- * Like {@link #expectLine(String)}, but also checks that the contents of the line is formed of
- * {@code numParts} space-separated parts.
- *
- * @param type the type of the line to expect, represented by the letter before the ':'.
- * @param numParts the number of parts to expect.
- * @return the part of the line after the ": ", split into {@code numParts} sections.
- */
- private String[] expectLineWithParts(String type, int numParts) throws IOException {
- final String[] parts = expectLine(type).strip().split(" ");
+ private String[] expectParts(String line, int numParts) {
+ final String[] parts = line.strip().split(" ");
if (parts.length != numParts) {
- throw new RuntimeException("Expected a '" + type + "' line with " + numParts
- + " parts, found one with " + parts.length);
+ throw new ParsingException(
+ "Expected a line with " + numParts + " space-separated parts, but found one "
+ + "with " + parts.length, mReader);
}
return parts;
}
- private static int[] hexStringBitmapToEventCodes(List<String> strs) {
+ private int parseInt(String s, int radix) {
+ try {
+ return Integer.parseInt(s, radix);
+ } catch (NumberFormatException ex) {
+ throw new ParsingException(
+ "'" + s + "' is not a valid integer of base " + radix, mReader);
+ }
+ }
+
+ private long parseLong(String s, int radix) {
+ try {
+ return Long.parseLong(s, radix);
+ } catch (NumberFormatException ex) {
+ throw new ParsingException("'" + s + "' is not a valid long of base " + radix, mReader);
+ }
+ }
+
+ private static int[] bitmapToEventCodes(List<Integer> bytes) {
final List<Integer> codes = new ArrayList<>();
- for (int iByte = 0; iByte < strs.size(); iByte++) {
- int b = Integer.parseInt(strs.get(iByte), 16);
- if (b < 0x0 || b > 0xff) {
- throw new RuntimeException("Bitmap part '" + strs.get(iByte)
- + "' invalid; parts must be between 00 and ff.");
- }
+ for (int iByte = 0; iByte < bytes.size(); iByte++) {
+ int b = bytes.get(iByte);
for (int iBit = 0; iBit < 8; iBit++) {
if ((b & 1) != 0) {
codes.add(iByte * 8 + iBit);
diff --git a/cmds/uinput/src/com/android/commands/uinput/Event.java b/cmds/uinput/src/com/android/commands/uinput/Event.java
index 5ec40e5d04e3..0f16a27aac1d 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Event.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Event.java
@@ -94,8 +94,9 @@ public class Event {
private int mId;
private Command mCommand;
private String mName;
- private int mVid;
- private int mPid;
+ private int mVendorId;
+ private int mProductId;
+ private int mVersionId;
private int mBusId;
private int[] mInjections;
private SparseArray<int[]> mConfiguration;
@@ -118,11 +119,15 @@ public class Event {
}
public int getVendorId() {
- return mVid;
+ return mVendorId;
}
public int getProductId() {
- return mPid;
+ return mProductId;
+ }
+
+ public int getVersionId() {
+ return mVersionId;
}
public int getBus() {
@@ -172,8 +177,8 @@ public class Event {
return "Event{id=" + mId
+ ", command=" + mCommand
+ ", name=" + mName
- + ", vid=" + mVid
- + ", pid=" + mPid
+ + ", vid=" + mVendorId
+ + ", pid=" + mProductId
+ ", busId=" + mBusId
+ ", events=" + Arrays.toString(mInjections)
+ ", configuration=" + mConfiguration
@@ -216,12 +221,16 @@ public class Event {
mEvent.mConfiguration = configuration;
}
- public void setVid(int vid) {
- mEvent.mVid = vid;
+ public void setVendorId(int vendorId) {
+ mEvent.mVendorId = vendorId;
+ }
+
+ public void setProductId(int productId) {
+ mEvent.mProductId = productId;
}
- public void setPid(int pid) {
- mEvent.mPid = pid;
+ public void setVersionId(int versionId) {
+ mEvent.mVersionId = versionId;
}
public void setBusId(int busId) {
diff --git a/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java b/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java
index 888ec5a1d33a..ed3ff33f7e52 100644
--- a/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java
+++ b/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java
@@ -60,8 +60,8 @@ public class JsonStyleParser implements EventParser {
case "command" -> eb.setCommand(
Event.Command.valueOf(mReader.nextString().toUpperCase()));
case "name" -> eb.setName(mReader.nextString());
- case "vid" -> eb.setVid(readInt());
- case "pid" -> eb.setPid(readInt());
+ case "vid" -> eb.setVendorId(readInt());
+ case "pid" -> eb.setProductId(readInt());
case "bus" -> eb.setBusId(readBus());
case "events" -> {
int[] injections = readInjectedEvents().stream()
diff --git a/cmds/uinput/src/com/android/commands/uinput/Uinput.java b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
index 684a12fc8f37..04df27987d58 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Uinput.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
@@ -60,6 +60,10 @@ public class Uinput {
stream = new FileInputStream(f);
}
(new Uinput(stream)).run();
+ } catch (EvemuParser.ParsingException e) {
+ System.err.println(e.makeErrorMessage());
+ error(e.makeErrorMessage(), e);
+ System.exit(1);
} catch (Exception e) {
error("Uinput injection failed.", e);
System.exit(1);
@@ -142,8 +146,9 @@ public class Uinput {
"Tried to send command \"" + e.getCommand() + "\" to an unregistered device!");
}
int id = e.getId();
- Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), e.getBus(),
- e.getConfiguration(), e.getFfEffectsMax(), e.getAbsInfo(), e.getPort());
+ Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(),
+ e.getVersionId(), e.getBus(), e.getConfiguration(), e.getFfEffectsMax(),
+ e.getAbsInfo(), e.getPort());
mDevices.append(id, d);
}
diff --git a/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java b/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java
index 6ee987fe07f1..06b0aac271ad 100644
--- a/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java
+++ b/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java
@@ -19,6 +19,8 @@ package com.android.commands.uinput.tests;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.fail;
+
import android.platform.test.annotations.Postsubmit;
import android.util.SparseArray;
@@ -68,7 +70,7 @@ public class EvemuParserTest {
assertThat(event.getBus()).isEqualTo(0x0001);
assertThat(event.getVendorId()).isEqualTo(0x1234);
assertThat(event.getProductId()).isEqualTo(0x5678);
- // TODO(b/302297266): check version ID once it's supported
+ assertThat(event.getVersionId()).isEqualTo(0x9abc);
}
@Test
@@ -241,6 +243,25 @@ public class EvemuParserTest {
}
@Test
+ public void testErrorLineNumberReporting() throws IOException {
+ StringReader reader = new StringReader("""
+ # EVEMU 1.3
+ N: ACME Widget
+ # Comment to make sure they're taken into account when numbering lines
+ I: 0001 1234 5678 9abc
+ 00 00 00 00 00 00 00 00 # Missing a type
+ E: 0.000001 0001 0015 0001 # KEY_Y press
+ E: 0.000001 0000 0000 0000 # SYN_REPORT
+ """);
+ try {
+ new EvemuParser(reader);
+ fail("Parser should have thrown an error about the line with the missing type.");
+ } catch (EvemuParser.ParsingException ex) {
+ assertThat(ex.makeErrorMessage()).startsWith("Parsing error on line 5:");
+ }
+ }
+
+ @Test
public void testFreeDesktopEvemuRecording() throws IOException {
// This is a real recording from FreeDesktop's evemu-record tool, as a basic compatibility
// check with the FreeDesktop tools.
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 01ca6d924605..ce5752fdbd8b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4211,10 +4211,18 @@ package android.content.pm {
public final class UserProperties implements android.os.Parcelable {
method public int describeContents();
+ method public int getShowInQuietMode();
+ method public int getShowInSharingSurfaces();
method public boolean isCredentialShareableWithParent();
method public boolean isMediaSharedWithParent();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.UserProperties> CREATOR;
+ field public static final int SHOW_IN_QUIET_MODE_DEFAULT = 2; // 0x2
+ field public static final int SHOW_IN_QUIET_MODE_HIDDEN = 1; // 0x1
+ field public static final int SHOW_IN_QUIET_MODE_PAUSED = 0; // 0x0
+ field public static final int SHOW_IN_SHARING_SURFACES_NO = 2; // 0x2
+ field public static final int SHOW_IN_SHARING_SURFACES_SEPARATE = 1; // 0x1
+ field public static final int SHOW_IN_SHARING_SURFACES_WITH_PARENT = 0; // 0x0
}
}
@@ -10560,6 +10568,7 @@ package android.os {
method @NonNull public java.util.List<android.os.UserHandle> getEnabledProfiles();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getMainUser();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getPreviousForegroundUser();
+ method @NonNull public String getProfileLabel();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableProfileCount(@NonNull String);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableUserCount(@NonNull String);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f3bad3aa82e0..1f7390c094f4 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -4201,8 +4201,13 @@ package android.window {
public static class WindowInfosListenerForTest.WindowInfo {
field @NonNull public final android.graphics.Rect bounds;
field public final int displayId;
+ field public final boolean isDuplicateTouchToWallpaper;
+ field public final boolean isFocusable;
+ field public final boolean isPreventSplitting;
+ field public final boolean isTouchable;
field public final boolean isTrustedOverlay;
field public final boolean isVisible;
+ field public final boolean isWatchOutsideTouch;
field @NonNull public final String name;
field @NonNull public final android.graphics.Matrix transform;
field @NonNull public final android.os.IBinder windowToken;
diff --git a/core/java/Android.bp b/core/java/Android.bp
index dfe3344a466a..fb1e16a27d0b 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -546,6 +546,15 @@ filegroup {
],
}
+// PackageManager common
+filegroup {
+ name: "framework-pm-common-shared-srcs",
+ srcs: [
+ "com/android/server/pm/pkg/AndroidPackage.java",
+ "com/android/server/pm/pkg/AndroidPackageSplit.java",
+ ],
+}
+
java_library {
name: "protolog-lib",
platform_apis: true,
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a4c3bb824502..87c86df6140d 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2934,6 +2934,15 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
+ public String getSuspendingPackage(String suspendedPackage) {
+ try {
+ return mPM.getSuspendingPackage(suspendedPackage, getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
public boolean isPackageSuspendedForUser(String packageName, int userId) {
try {
return mPM.isPackageSuspendedForUser(packageName, userId);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index df6badcffe8e..d54074818b41 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -328,7 +328,7 @@ interface IActivityTaskManager {
* A splash screen view has copied.
*/
void onSplashScreenViewCopyFinished(int taskId,
- in SplashScreenView.SplashScreenViewParcelable material);
+ in @nullable SplashScreenView.SplashScreenViewParcelable material);
/**
* When the Picture-in-picture state has changed.
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 7be4b3611d00..fb0edb954539 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -24,8 +24,15 @@ flag {
flag {
name: "lifetime_extension_refactor"
- namespace: "systemui"
- description: "Enables moving notification lifetime extension management from SystemUI to "
- "Notification Manager Service"
- bug: "299448097"
-} \ No newline at end of file
+ namespace: "systemui"
+ description: "Enables moving notification lifetime extension management from SystemUI to "
+ "Notification Manager Service"
+ bug: "299448097"
+}
+
+flag {
+ name: "visit_risky_uris"
+ namespace: "systemui"
+ description: "Guards the security fix that ensures all URIs in intents and Person.java are valid"
+ bug: "281044385"
+}
diff --git a/core/java/android/app/time/TEST_MAPPING b/core/java/android/app/time/TEST_MAPPING
index 47a152aa6cca..0f7a0700b370 100644
--- a/core/java/android/app/time/TEST_MAPPING
+++ b/core/java/android/app/time/TEST_MAPPING
@@ -7,12 +7,20 @@
"include-filter": "android.app."
}
]
+ },
+ {
+ "name": "CtsTimeTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
],
// TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
"postsubmit": [
{
- "name": "FrameworksServicesTests",
+ "name": "FrameworksTimeServicesTests",
"options": [
{
"include-filter": "com.android.server.timezonedetector."
@@ -21,14 +29,6 @@
"include-filter": "com.android.server.timedetector."
}
]
- },
- {
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
}
]
}
diff --git a/core/java/android/app/timedetector/TEST_MAPPING b/core/java/android/app/timedetector/TEST_MAPPING
index 9517fb99b04a..43dd82f8a26e 100644
--- a/core/java/android/app/timedetector/TEST_MAPPING
+++ b/core/java/android/app/timedetector/TEST_MAPPING
@@ -7,23 +7,23 @@
"include-filter": "android.app."
}
]
- }
- ],
- // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
- "postsubmit": [
+ },
{
- "name": "FrameworksServicesTests",
+ "name": "CtsTimeTestCases",
"options": [
{
- "include-filter": "com.android.server.timedetector."
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
- },
+ }
+ ],
+ // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
+ "postsubmit": [
{
- "name": "CtsTimeTestCases",
+ "name": "FrameworksTimeServicesTests",
"options": [
{
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "include-filter": "com.android.server.timedetector."
}
]
}
diff --git a/core/java/android/app/timezonedetector/TEST_MAPPING b/core/java/android/app/timezonedetector/TEST_MAPPING
index fd41b869efaf..2be5614b54a5 100644
--- a/core/java/android/app/timezonedetector/TEST_MAPPING
+++ b/core/java/android/app/timezonedetector/TEST_MAPPING
@@ -7,23 +7,23 @@
"include-filter": "android.app."
}
]
- }
- ],
- // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
- "postsubmit": [
+ },
{
- "name": "FrameworksServicesTests",
+ "name": "CtsTimeTestCases",
"options": [
{
- "include-filter": "com.android.server.timezonedetector."
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
- },
+ }
+ ],
+ // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
+ "postsubmit": [
{
- "name": "CtsTimeTestCases",
+ "name": "FrameworksTimeServicesTests",
"options": [
{
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "include-filter": "com.android.server.timezonedetector."
}
]
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index babfba13afcd..98623de810c4 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -312,6 +312,8 @@ interface IPackageManager {
Bundle getSuspendedPackageAppExtras(String packageName, int userId);
+ String getSuspendingPackage(String packageName, int userId);
+
/**
* Backup/restore support - only the system uid may use these.
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fe31c9dbf27d..6775f9b8d84d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -9965,6 +9965,21 @@ public abstract class PackageManager {
}
/**
+ * Get the name of the package that suspended the given package. Packages can be suspended by
+ * device administrators or apps holding {@link android.Manifest.permission#MANAGE_USERS} or
+ * {@link android.Manifest.permission#SUSPEND_APPS}.
+ *
+ * @param suspendedPackage The package that has been suspended.
+ * @return Name of the package that suspended the given package. Returns {@code null} if the
+ * given package is not currently suspended and the platform package name - i.e.
+ * {@code "android"} - if the package was suspended by a device admin.
+ * @hide
+ */
+ public @Nullable String getSuspendingPackage(@NonNull String suspendedPackage) {
+ throw new UnsupportedOperationException("getSuspendingPackage not implemented");
+ }
+
+ /**
* Query if an app is currently stopped.
*
* @return {@code true} if the given package is stopped, {@code false} otherwise
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index f532c4cffcc4..445ca0c98416 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -19,6 +19,7 @@ package android.content.pm;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.Parcel;
@@ -49,7 +50,8 @@ public final class UserProperties implements Parcelable {
private static final String ATTR_SHOW_IN_LAUNCHER = "showInLauncher";
private static final String ATTR_START_WITH_PARENT = "startWithParent";
private static final String ATTR_SHOW_IN_SETTINGS = "showInSettings";
- private static final String ATTR_HIDE_IN_SETTINGS_IN_QUIET_MODE = "hideInSettingsInQuietMode";
+ private static final String ATTR_SHOW_IN_QUIET_MODE = "showInQuietMode";
+ private static final String ATTR_SHOW_IN_SHARING_SURFACES = "showInSharingSurfaces";
private static final String ATTR_INHERIT_DEVICE_POLICY = "inheritDevicePolicy";
private static final String ATTR_USE_PARENTS_CONTACTS = "useParentsContacts";
private static final String ATTR_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA =
@@ -81,7 +83,8 @@ public final class UserProperties implements Parcelable {
INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT,
INDEX_DELETE_APP_WITH_PARENT,
INDEX_ALWAYS_VISIBLE,
- INDEX_HIDE_IN_SETTINGS_IN_QUIET_MODE,
+ INDEX_SHOW_IN_QUIET_MODE,
+ INDEX_SHOW_IN_SHARING_SURFACES,
INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE,
})
@Retention(RetentionPolicy.SOURCE)
@@ -99,8 +102,9 @@ public final class UserProperties implements Parcelable {
private static final int INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT = 9;
private static final int INDEX_DELETE_APP_WITH_PARENT = 10;
private static final int INDEX_ALWAYS_VISIBLE = 11;
- private static final int INDEX_HIDE_IN_SETTINGS_IN_QUIET_MODE = 12;
+ private static final int INDEX_SHOW_IN_QUIET_MODE = 12;
private static final int INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE = 13;
+ private static final int INDEX_SHOW_IN_SHARING_SURFACES = 14;
/** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
private long mPropertiesPresent = 0;
@@ -286,6 +290,81 @@ public final class UserProperties implements Parcelable {
*/
public static final int CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING = 1;
+ /**
+ * Possible values for the profile visibility when in quiet mode. This affects the profile data
+ * and apps surfacing in Settings, sharing surfaces, and file picker surfaces. It signifies
+ * whether the profile data and apps will be shown or not.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "SHOW_IN_QUIET_MODE_",
+ value = {
+ SHOW_IN_QUIET_MODE_PAUSED,
+ SHOW_IN_QUIET_MODE_HIDDEN,
+ SHOW_IN_QUIET_MODE_DEFAULT,
+ }
+ )
+ public @interface ShowInQuietMode {
+ }
+
+ /**
+ * Indicates that the profile should still be visible in quiet mode but should be shown as
+ * paused (e.g. by greying out its icons).
+ */
+ @SuppressLint("UnflaggedApi") // b/306636213
+ public static final int SHOW_IN_QUIET_MODE_PAUSED = 0;
+ /**
+ * Indicates that the profile should not be visible when the profile is in quiet mode.
+ * For example, the profile should not be shown in tabbed views in Settings, files sharing
+ * surfaces etc when in quiet mode.
+ */
+ @SuppressLint("UnflaggedApi") // b/306636213
+ public static final int SHOW_IN_QUIET_MODE_HIDDEN = 1;
+ /**
+ * Indicates that quiet mode should not have any effect on the profile visibility. If the
+ * profile is meant to be visible, it will remain visible and vice versa.
+ */
+ @SuppressLint("UnflaggedApi") // b/306636213
+ public static final int SHOW_IN_QUIET_MODE_DEFAULT = 2;
+
+ /**
+ * Possible values for the profile apps visibility in sharing surfaces. This indicates the
+ * profile data and apps should be shown in separate tabs or mixed with its parent user's data
+ * and apps in sharing surfaces and file picker surfaces.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "SHOW_IN_SHARING_SURFACES_",
+ value = {
+ SHOW_IN_SHARING_SURFACES_SEPARATE,
+ SHOW_IN_SHARING_SURFACES_WITH_PARENT,
+ SHOW_IN_SHARING_SURFACES_NO,
+ }
+ )
+ public @interface ShowInSharingSurfaces {
+ }
+
+ /**
+ * Indicates that the profile data and apps should be shown in sharing surfaces intermixed with
+ * parent user's data and apps.
+ */
+ @SuppressLint("UnflaggedApi") // b/306636213
+ public static final int SHOW_IN_SHARING_SURFACES_WITH_PARENT = SHOW_IN_LAUNCHER_WITH_PARENT;
+
+ /**
+ * Indicates that the profile data and apps should be shown in sharing surfaces separate from
+ * parent user's data and apps.
+ */
+ @SuppressLint("UnflaggedApi") // b/306636213
+ public static final int SHOW_IN_SHARING_SURFACES_SEPARATE = SHOW_IN_LAUNCHER_SEPARATE;
+
+ /**
+ * Indicates that the profile data and apps should not be shown in sharing surfaces at all.
+ */
+ @SuppressLint("UnflaggedApi") // b/306636213
+ public static final int SHOW_IN_SHARING_SURFACES_NO = SHOW_IN_LAUNCHER_NO;
/**
* Creates a UserProperties (intended for the SystemServer) that stores a reference to the given
@@ -331,7 +410,6 @@ public final class UserProperties implements Parcelable {
if (hasManagePermission) {
// Add items that require MANAGE_USERS or stronger.
setShowInSettings(orig.getShowInSettings());
- setHideInSettingsInQuietMode(orig.getHideInSettingsInQuietMode());
setUseParentsContacts(orig.getUseParentsContacts());
setAuthAlwaysRequiredToDisableQuietMode(
orig.isAuthAlwaysRequiredToDisableQuietMode());
@@ -343,6 +421,8 @@ public final class UserProperties implements Parcelable {
setShowInLauncher(orig.getShowInLauncher());
setMediaSharedWithParent(orig.isMediaSharedWithParent());
setCredentialShareableWithParent(orig.isCredentialShareableWithParent());
+ setShowInQuietMode(orig.getShowInQuietMode());
+ setShowInSharingSurfaces(orig.getShowInSharingSurfaces());
}
/**
@@ -419,40 +499,59 @@ public final class UserProperties implements Parcelable {
private @ShowInSettings int mShowInSettings;
/**
- * Returns whether a user should be shown in the Settings app depending on the quiet mode.
- * This is generally inapplicable for non-profile users.
- *
- * <p> {@link #getShowInSettings()} returns whether / how a user should be shown in Settings.
- * However, if this behaviour should be changed based on the quiet mode of the user, then this
- * property can be used. If the property is not set then the user is shown in the Settings app
- * irrespective of whether the user is in quiet mode or not. If the property is set, then the
- * user is shown in the Settings app only if the user is not in the quiet mode. Please note that
- * this property takes effect only if {@link #getShowInSettings()} does not return
- * {@link #SHOW_IN_SETTINGS_NO}.
- *
- * <p> The caller must have {@link android.Manifest.permission#MANAGE_USERS} to query this
- * property.
+ * Returns whether a user should be shown in the Settings and sharing surfaces depending on the
+ * {@link android.os.UserManager#requestQuietModeEnabled(boolean, android.os.UserHandle)
+ * quiet mode}. This is only applicable to profile users since the quiet mode concept is only
+ * applicable to profile users.
*
- * @return true if a profile should be shown in the Settings only when the user is not in the
- * quiet mode.
+ * <p> Please note that, in Settings, this property takes effect only if
+ * {@link #getShowInSettings()} does not return {@link #SHOW_IN_SETTINGS_NO}.
+ * Also note that in Sharing surfaces this property takes effect only if
+ * {@link #getShowInSharingSurfaces()} does not return {@link #SHOW_IN_SHARING_SURFACES_NO}.
*
- * See also {@link #getShowInSettings()}, {@link #setShowInSettings(int)},
- * {@link ShowInSettings}
+ * @return One of {@link #SHOW_IN_QUIET_MODE_HIDDEN},
+ * {@link #SHOW_IN_QUIET_MODE_PAUSED}, or
+ * {@link #SHOW_IN_QUIET_MODE_DEFAULT} depending on whether the profile should be
+ * shown in quiet mode or not.
+ */
+ @SuppressLint("UnflaggedApi") // b/306636213
+ public @ShowInQuietMode int getShowInQuietMode() {
+ // NOTE: Launcher currently does not make use of this property.
+ if (isPresent(INDEX_SHOW_IN_QUIET_MODE)) return mShowInQuietMode;
+ if (mDefaultProperties != null) return mDefaultProperties.mShowInQuietMode;
+ throw new SecurityException(
+ "You don't have permission to query ShowInQuietMode");
+ }
+ /** @hide */
+ public void setShowInQuietMode(@ShowInQuietMode int showInQuietMode) {
+ this.mShowInQuietMode = showInQuietMode;
+ setPresent(INDEX_SHOW_IN_QUIET_MODE);
+ }
+ private int mShowInQuietMode;
+
+ /**
+ * Returns whether a user's data and apps should be shown in sharing surfaces in a separate tab
+ * or mixed with the parent user's data/apps. This is only applicable to profile users.
*
- * @hide
+ * @return One of {@link #SHOW_IN_SHARING_SURFACES_NO},
+ * {@link #SHOW_IN_SHARING_SURFACES_SEPARATE}, or
+ * {@link #SHOW_IN_SHARING_SURFACES_WITH_PARENT} depending on whether the profile
+ * should be shown separate from its parent's data, mixed with the parent's data, or
+ * not shown at all.
*/
- public boolean getHideInSettingsInQuietMode() {
- if (isPresent(INDEX_HIDE_IN_SETTINGS_IN_QUIET_MODE)) return mHideInSettingsInQuietMode;
- if (mDefaultProperties != null) return mDefaultProperties.mHideInSettingsInQuietMode;
+ @SuppressLint("UnflaggedApi") // b/306636213
+ public @ShowInSharingSurfaces int getShowInSharingSurfaces() {
+ if (isPresent(INDEX_SHOW_IN_SHARING_SURFACES)) return mShowInSharingSurfaces;
+ if (mDefaultProperties != null) return mDefaultProperties.mShowInSharingSurfaces;
throw new SecurityException(
- "You don't have permission to query HideInSettingsInQuietMode");
+ "You don't have permission to query ShowInSharingSurfaces");
}
/** @hide */
- public void setHideInSettingsInQuietMode(boolean hideInSettingsInQuietMode) {
- this.mHideInSettingsInQuietMode = hideInSettingsInQuietMode;
- setPresent(INDEX_HIDE_IN_SETTINGS_IN_QUIET_MODE);
+ public void setShowInSharingSurfaces(@ShowInSharingSurfaces int showInSharingSurfaces) {
+ this.mShowInSharingSurfaces = showInSharingSurfaces;
+ setPresent(INDEX_SHOW_IN_SHARING_SURFACES);
}
- private boolean mHideInSettingsInQuietMode;
+ private int mShowInSharingSurfaces;
/**
* Returns whether a profile should be started when its parent starts (unless in quiet mode).
@@ -799,8 +898,11 @@ public final class UserProperties implements Parcelable {
case ATTR_SHOW_IN_SETTINGS:
setShowInSettings(parser.getAttributeInt(i));
break;
- case ATTR_HIDE_IN_SETTINGS_IN_QUIET_MODE:
- setHideInSettingsInQuietMode(parser.getAttributeBoolean(i));
+ case ATTR_SHOW_IN_QUIET_MODE:
+ setShowInQuietMode(parser.getAttributeInt(i));
+ break;
+ case ATTR_SHOW_IN_SHARING_SURFACES:
+ setShowInSharingSurfaces(parser.getAttributeInt(i));
break;
case ATTR_INHERIT_DEVICE_POLICY:
setInheritDevicePolicy(parser.getAttributeInt(i));
@@ -858,9 +960,12 @@ public final class UserProperties implements Parcelable {
if (isPresent(INDEX_SHOW_IN_SETTINGS)) {
serializer.attributeInt(null, ATTR_SHOW_IN_SETTINGS, mShowInSettings);
}
- if (isPresent(INDEX_HIDE_IN_SETTINGS_IN_QUIET_MODE)) {
- serializer.attributeBoolean(null, ATTR_HIDE_IN_SETTINGS_IN_QUIET_MODE,
- mHideInSettingsInQuietMode);
+ if (isPresent(INDEX_SHOW_IN_QUIET_MODE)) {
+ serializer.attributeInt(null, ATTR_SHOW_IN_QUIET_MODE,
+ mShowInQuietMode);
+ }
+ if (isPresent(INDEX_SHOW_IN_SHARING_SURFACES)) {
+ serializer.attributeInt(null, ATTR_SHOW_IN_SHARING_SURFACES, mShowInSharingSurfaces);
}
if (isPresent(INDEX_INHERIT_DEVICE_POLICY)) {
serializer.attributeInt(null, ATTR_INHERIT_DEVICE_POLICY,
@@ -912,7 +1017,8 @@ public final class UserProperties implements Parcelable {
dest.writeInt(mShowInLauncher);
dest.writeBoolean(mStartWithParent);
dest.writeInt(mShowInSettings);
- dest.writeBoolean(mHideInSettingsInQuietMode);
+ dest.writeInt(mShowInQuietMode);
+ dest.writeInt(mShowInSharingSurfaces);
dest.writeInt(mInheritDevicePolicy);
dest.writeBoolean(mUseParentsContacts);
dest.writeBoolean(mUpdateCrossProfileIntentFiltersOnOTA);
@@ -936,7 +1042,8 @@ public final class UserProperties implements Parcelable {
mShowInLauncher = source.readInt();
mStartWithParent = source.readBoolean();
mShowInSettings = source.readInt();
- mHideInSettingsInQuietMode = source.readBoolean();
+ mShowInQuietMode = source.readInt();
+ mShowInSharingSurfaces = source.readInt();
mInheritDevicePolicy = source.readInt();
mUseParentsContacts = source.readBoolean();
mUpdateCrossProfileIntentFiltersOnOTA = source.readBoolean();
@@ -974,7 +1081,10 @@ public final class UserProperties implements Parcelable {
private @ShowInLauncher int mShowInLauncher = SHOW_IN_LAUNCHER_WITH_PARENT;
private boolean mStartWithParent = false;
private @ShowInSettings int mShowInSettings = SHOW_IN_SETTINGS_WITH_PARENT;
- private boolean mHideInSettingsInQuietMode = false;
+ private @ShowInQuietMode int mShowInQuietMode =
+ SHOW_IN_QUIET_MODE_PAUSED;
+ private @ShowInSharingSurfaces int mShowInSharingSurfaces =
+ SHOW_IN_SHARING_SURFACES_SEPARATE;
private @InheritDevicePolicy int mInheritDevicePolicy = INHERIT_DEVICE_POLICY_NO;
private boolean mUseParentsContacts = false;
private boolean mUpdateCrossProfileIntentFiltersOnOTA = false;
@@ -1005,9 +1115,15 @@ public final class UserProperties implements Parcelable {
return this;
}
- /** Sets the value for {@link #mHideInSettingsInQuietMode} */
- public Builder setHideInSettingsInQuietMode(boolean hideInSettingsInQuietMode) {
- mHideInSettingsInQuietMode = hideInSettingsInQuietMode;
+ /** Sets the value for {@link #mShowInQuietMode} */
+ public Builder setShowInQuietMode(@ShowInQuietMode int showInQuietMode) {
+ mShowInQuietMode = showInQuietMode;
+ return this;
+ }
+
+ /** Sets the value for {@link #mShowInSharingSurfaces}. */
+ public Builder setShowInSharingSurfaces(@ShowInSharingSurfaces int showInSharingSurfaces) {
+ mShowInSharingSurfaces = showInSharingSurfaces;
return this;
}
@@ -1081,7 +1197,8 @@ public final class UserProperties implements Parcelable {
mShowInLauncher,
mStartWithParent,
mShowInSettings,
- mHideInSettingsInQuietMode,
+ mShowInQuietMode,
+ mShowInSharingSurfaces,
mInheritDevicePolicy,
mUseParentsContacts,
mUpdateCrossProfileIntentFiltersOnOTA,
@@ -1100,7 +1217,8 @@ public final class UserProperties implements Parcelable {
@ShowInLauncher int showInLauncher,
boolean startWithParent,
@ShowInSettings int showInSettings,
- boolean hideInSettingsInQuietMode,
+ @ShowInQuietMode int showInQuietMode,
+ @ShowInSharingSurfaces int showInSharingSurfaces,
@InheritDevicePolicy int inheritDevicePolicy,
boolean useParentsContacts, boolean updateCrossProfileIntentFiltersOnOTA,
@CrossProfileIntentFilterAccessControlLevel int crossProfileIntentFilterAccessControl,
@@ -1114,7 +1232,8 @@ public final class UserProperties implements Parcelable {
setShowInLauncher(showInLauncher);
setStartWithParent(startWithParent);
setShowInSettings(showInSettings);
- setHideInSettingsInQuietMode(hideInSettingsInQuietMode);
+ setShowInQuietMode(showInQuietMode);
+ setShowInSharingSurfaces(showInSharingSurfaces);
setInheritDevicePolicy(inheritDevicePolicy);
setUseParentsContacts(useParentsContacts);
setUpdateCrossProfileIntentFiltersOnOTA(updateCrossProfileIntentFiltersOnOTA);
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 9ec082ab8eea..6c6b33b8d716 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -42,3 +42,10 @@ flag {
description: "Allow using all cpu cores during a user switch."
bug: "308105403"
}
+
+flag {
+ name: "enable_biometrics_to_unlock_private_space"
+ namespace: "profile_experiences"
+ description: "Add support to unlock the private space using biometrics"
+ bug: "312184187"
+}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 330b992ef308..c0d1fb9c6a88 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -131,6 +131,7 @@ interface IUserManager {
int getUserBadgeDarkColorResId(int userId);
int getUserStatusBarIconResId(int userId);
boolean hasBadge(int userId);
+ int getProfileLabelResId(int userId);
boolean isUserUnlocked(int userId);
boolean isUserRunning(int userId);
boolean isUserForeground(int userId);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 08d6e028f08c..ec6d20fbc0f5 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -5693,6 +5693,44 @@ public class UserManager {
}
/**
+ * Returns the string/label that should be used to represent the context user. For example,
+ * this string can represent a profile in tabbed views. This is only applicable to
+ * {@link #isProfile() profile users}. This string is translated to the device default language.
+ *
+ * @return String representing the label for the context user.
+ *
+ * @throws android.content.res.Resources.NotFoundException if the user does not have a label
+ * defined.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SuppressLint("UnflaggedApi") // b/306636213
+ @UserHandleAware(
+ requiresAnyOfPermissionsIfNotCallerProfileGroup = {
+ Manifest.permission.MANAGE_USERS,
+ Manifest.permission.QUERY_USERS,
+ Manifest.permission.INTERACT_ACROSS_USERS})
+ public @NonNull String getProfileLabel() {
+ if (isManagedProfile(mUserId)) {
+ DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+ return dpm.getResources().getString(
+ android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_TAB,
+ () -> getDefaultProfileLabel(mUserId));
+ }
+ return getDefaultProfileLabel(mUserId);
+ }
+
+ private String getDefaultProfileLabel(int userId) {
+ try {
+ final int resourceId = mService.getProfileLabelResId(userId);
+ return Resources.getSystem().getString(resourceId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* If the user is a {@link UserManager#isProfile profile}, checks if the user
* shares media with its parent user (the user that created this profile).
* Returns false for any other type of user.
diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig
new file mode 100644
index 000000000000..597838305a91
--- /dev/null
+++ b/core/java/android/service/chooser/flags.aconfig
@@ -0,0 +1,9 @@
+package: "android.service.chooser"
+
+flag {
+ name: "support_nfc_resolver"
+ namespace: "systemui"
+ description: "This flag controls the new NFC 'resolver' activity"
+ bug: "268089816"
+}
+
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 9f886c826174..d131dc9a4c7d 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -69,6 +69,7 @@ public final class InputDevice implements Parcelable {
private final String mName;
private final int mVendorId;
private final int mProductId;
+ private final int mDeviceBus;
private final String mDescriptor;
private final InputDeviceIdentifier mIdentifier;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -468,8 +469,8 @@ public final class InputDevice implements Parcelable {
* Called by native code
*/
private InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
- int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
- KeyCharacterMap keyCharacterMap, @Nullable String keyboardLanguageTag,
+ int productId, int deviceBus, String descriptor, boolean isExternal, int sources,
+ int keyboardType, KeyCharacterMap keyCharacterMap, @Nullable String keyboardLanguageTag,
@Nullable String keyboardLayoutType, boolean hasVibrator, boolean hasMicrophone,
boolean hasButtonUnderPad, boolean hasSensor, boolean hasBattery, int usiVersionMajor,
int usiVersionMinor, int associatedDisplayId) {
@@ -479,6 +480,7 @@ public final class InputDevice implements Parcelable {
mName = name;
mVendorId = vendorId;
mProductId = productId;
+ mDeviceBus = deviceBus;
mDescriptor = descriptor;
mIsExternal = isExternal;
mSources = sources;
@@ -512,6 +514,7 @@ public final class InputDevice implements Parcelable {
mName = in.readString();
mVendorId = in.readInt();
mProductId = in.readInt();
+ mDeviceBus = in.readInt();
mDescriptor = in.readString();
mIsExternal = in.readInt() != 0;
mSources = in.readInt();
@@ -551,6 +554,7 @@ public final class InputDevice implements Parcelable {
private String mName = "";
private int mVendorId = 0;
private int mProductId = 0;
+ private int mDeviceBus = 0;
private String mDescriptor = "";
private boolean mIsExternal = false;
private int mSources = 0;
@@ -604,6 +608,12 @@ public final class InputDevice implements Parcelable {
return this;
}
+ /** @see InputDevice#getDeviceBus() */
+ public Builder setDeviceBus(int deviceBus) {
+ mDeviceBus = deviceBus;
+ return this;
+ }
+
/** @see InputDevice#getDescriptor() */
public Builder setDescriptor(String descriptor) {
mDescriptor = descriptor;
@@ -705,6 +715,7 @@ public final class InputDevice implements Parcelable {
mName,
mVendorId,
mProductId,
+ mDeviceBus,
mDescriptor,
mIsExternal,
mSources,
@@ -847,6 +858,21 @@ public final class InputDevice implements Parcelable {
}
/**
+ * Gets the device bus used by given device, if available.
+ * <p>
+ * The device bus is the communication system used for transferring data
+ * (e.g. USB, Bluetooth etc.). This value comes from the kernel (from input.h).
+ * A value of 0 will be assigned where the device bus is not available.
+ * </p>
+ *
+ * @return The device bus of a given device
+ * @hide
+ */
+ public int getDeviceBus() {
+ return mDeviceBus;
+ }
+
+ /**
* Gets the input device descriptor, which is a stable identifier for an input device.
* <p>
* An input device descriptor uniquely identifies an input device. Its value
@@ -1448,6 +1474,7 @@ public final class InputDevice implements Parcelable {
out.writeString(mName);
out.writeInt(mVendorId);
out.writeInt(mProductId);
+ out.writeInt(mDeviceBus);
out.writeString(mDescriptor);
out.writeInt(mIsExternal ? 1 : 0);
out.writeInt(mSources);
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 542c783c9dff..14ec14bf7cfc 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -60,6 +60,7 @@ import android.view.inputmethod.BaseInputConnection;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
+import com.android.modules.expresslog.Counter;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -68,6 +69,7 @@ import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Main session associated with a context.
@@ -81,6 +83,9 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
private static final String TAG = MainContentCaptureSession.class.getSimpleName();
+ private static final String CONTENT_CAPTURE_WRONG_THREAD_METRIC_ID =
+ "content_capture.value_content_capture_wrong_thread_count";
+
// For readability purposes...
private static final boolean FORCE_FLUSH = true;
@@ -165,6 +170,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
@Nullable
private final LocalLog mFlushHistory;
+ private final AtomicInteger mWrongThreadCount = new AtomicInteger(0);
+
/**
* Binder object used to update the session state.
*/
@@ -701,6 +708,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
+ getDebugState());
}
+ reportWrongThreadMetric();
try {
mSystemServerInterface.finishSession(mId);
} catch (RemoteException e) {
@@ -1040,20 +1048,27 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
/**
- * Checks that the current work is running on the assigned thread from {@code mHandler}.
+ * Checks that the current work is running on the assigned thread from {@code mHandler} and
+ * count the number of times running on the wrong thread.
*
* <p>It is not guaranteed that the callers always invoke function from a single thread.
* Therefore, accessing internal properties in {@link MainContentCaptureSession} should
* always delegate to the assigned thread from {@code mHandler} for synchronization.</p>
*/
private void checkOnContentCaptureThread() {
- // TODO(b/309411951): Add metrics to track the issue instead.
final boolean onContentCaptureThread = mHandler.getLooper().isCurrentThread();
if (!onContentCaptureThread) {
+ mWrongThreadCount.incrementAndGet();
Log.e(TAG, "MainContentCaptureSession running on " + Thread.currentThread());
}
}
+ /** Reports number of times running on the wrong thread. */
+ private void reportWrongThreadMetric() {
+ Counter.logIncrement(
+ CONTENT_CAPTURE_WRONG_THREAD_METRIC_ID, mWrongThreadCount.getAndSet(0));
+ }
+
/**
* Ensures that {@code r} will be running on the assigned thread.
*
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 1b9ff44c9185..8e89541647c3 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -16,6 +16,8 @@
package android.webkit;
+import static android.webkit.Flags.updateServiceV2;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -205,6 +207,9 @@ public final class WebViewDelegate {
* Returns whether WebView should run in multiprocess mode.
*/
public boolean isMultiProcessEnabled() {
+ if (updateServiceV2()) {
+ return true;
+ }
try {
return WebViewFactory.getUpdateService().isMultiProcessEnabled();
} catch (RemoteException e) {
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index bc7a5fda6f7a..e14ae72ee7a5 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -16,6 +16,8 @@
package android.webkit;
+import static android.webkit.Flags.updateServiceV2;
+
import android.content.pm.PackageInfo;
import android.os.Build;
import android.os.ChildZygoteProcess;
@@ -50,8 +52,8 @@ public class WebViewZygote {
private static PackageInfo sPackage;
/**
- * Flag for whether multi-process WebView is enabled. If this is {@code false}, the zygote
- * will not be started.
+ * Flag for whether multi-process WebView is enabled. If this is {@code false}, the zygote will
+ * not be started. Should be removed entirely after we remove the updateServiceV2 flag.
*/
@GuardedBy("sLock")
private static boolean sMultiprocessEnabled = false;
@@ -73,11 +75,19 @@ public class WebViewZygote {
public static boolean isMultiprocessEnabled() {
synchronized (sLock) {
- return sMultiprocessEnabled && sPackage != null;
+ if (updateServiceV2()) {
+ return sPackage != null;
+ } else {
+ return sMultiprocessEnabled && sPackage != null;
+ }
}
}
public static void setMultiprocessEnabled(boolean enabled) {
+ if (updateServiceV2()) {
+ throw new IllegalStateException(
+ "setMultiprocessEnabled shouldn't be called if update_service_v2 flag is set.");
+ }
synchronized (sLock) {
sMultiprocessEnabled = enabled;
diff --git a/core/java/android/window/WindowInfosListenerForTest.java b/core/java/android/window/WindowInfosListenerForTest.java
index 35ce72620d09..34c639974bfd 100644
--- a/core/java/android/window/WindowInfosListenerForTest.java
+++ b/core/java/android/window/WindowInfosListenerForTest.java
@@ -19,6 +19,7 @@ package android.window;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -87,6 +88,38 @@ public class WindowInfosListenerForTest {
@NonNull
public final Matrix transform;
+ /**
+ * True if the window is touchable.
+ */
+ @SuppressLint("UnflaggedApi") // The API is only used for tests.
+ public final boolean isTouchable;
+
+ /**
+ * True if the window is focusable.
+ */
+ @SuppressLint("UnflaggedApi") // The API is only used for tests.
+ public final boolean isFocusable;
+
+ /**
+ * True if the window is preventing splitting
+ */
+ @SuppressLint("UnflaggedApi") // The API is only used for tests.
+ public final boolean isPreventSplitting;
+
+ /**
+ * True if the window duplicates touches received to wallpaper.
+ */
+ @SuppressLint("UnflaggedApi") // The API is only used for tests.
+ public final boolean isDuplicateTouchToWallpaper;
+
+ /**
+ * True if the window is listening for when there is a touch DOWN event
+ * occurring outside its touchable bounds. When such an event occurs,
+ * this window will receive a MotionEvent with ACTION_OUTSIDE.
+ */
+ @SuppressLint("UnflaggedApi") // The API is only used for tests.
+ public final boolean isWatchOutsideTouch;
+
WindowInfo(@NonNull IBinder windowToken, @NonNull String name, int displayId,
@NonNull Rect bounds, int inputConfig, @NonNull Matrix transform) {
this.windowToken = windowToken;
@@ -96,6 +129,14 @@ public class WindowInfosListenerForTest {
this.isTrustedOverlay = (inputConfig & InputConfig.TRUSTED_OVERLAY) != 0;
this.isVisible = (inputConfig & InputConfig.NOT_VISIBLE) == 0;
this.transform = transform;
+ this.isTouchable = (inputConfig & InputConfig.NOT_TOUCHABLE) == 0;
+ this.isFocusable = (inputConfig & InputConfig.NOT_FOCUSABLE) == 0;
+ this.isPreventSplitting = (inputConfig
+ & InputConfig.PREVENT_SPLITTING) != 0;
+ this.isDuplicateTouchToWallpaper = (inputConfig
+ & InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER) != 0;
+ this.isWatchOutsideTouch = (inputConfig
+ & InputConfig.WATCH_OUTSIDE_TOUCH) != 0;
}
@Override
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 7f93213bf884..29932f342b74 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -48,3 +48,11 @@ flag {
is_fixed_read_only: true
bug: "262477923"
}
+
+flag {
+ namespace: "window_surfaces"
+ name: "secure_window_state"
+ description: "Move SC secure flag to WindowState level"
+ is_fixed_read_only: true
+ bug: "308662081"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 4705dc5db90b..31a3ebd9b32e 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -8,6 +8,13 @@ flag {
}
flag {
+ name: "edge_to_edge_by_default"
+ namespace: "windowing_frontend"
+ description: "Make app go edge-to-edge by default when targeting SDK 35 or greater"
+ bug: "309578419"
+}
+
+flag {
name: "defer_display_updates"
namespace: "window_manager"
description: "Feature flag for deferring DisplayManager updates to WindowManager if Shell transition is running"
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageHidden.java b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageHidden.java
index 1fafdf9035e6..0d7b43368821 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageHidden.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageHidden.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.parsing.pkg;
+package com.android.internal.pm.parsing.pkg;
import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
@@ -22,16 +22,18 @@ import android.content.pm.PackageInfo;
/**
* Methods that normal consumers should not have access to. This usually means the field is stateful
- * or deprecated and should be access through {@link AndroidPackageUtils} or a system manager
- * class.
+ * or deprecated and should be access through
+ * {@link com.android.server.pm.parsing.pkg.AndroidPackageUtils} or a system manager class.
* <p>
* This is a separate interface, not implemented by the base {@link AndroidPackage} because Java
* doesn't support non-public interface methods. The class must be cast to this interface.
* <p>
* Because they exist in different packages, some methods are duplicated from
* android.content.pm.parsing.ParsingPackageHidden.
+ * @hide
*/
-interface AndroidPackageHidden {
+// TODO: remove public after moved PackageImpl and AndroidPackageUtils
+public interface AndroidPackageHidden {
/**
* @see ApplicationInfo#primaryCpuAbi
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageInternal.java
index 9eca7d651dea..6f8e658da50c 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageInternal.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.parsing.pkg;
+package com.android.internal.pm.parsing.pkg;
import android.annotation.NonNull;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
index 85f8f7609c2a..7ef0b4864c84 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.parsing.pkg;
+package com.android.internal.pm.parsing.pkg;
import android.content.pm.SigningDetails;
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackageSplitImpl.java b/core/java/com/android/internal/pm/pkg/AndroidPackageSplitImpl.java
index c0f2c25a66a4..3c564e9f401e 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackageSplitImpl.java
+++ b/core/java/com/android/internal/pm/pkg/AndroidPackageSplitImpl.java
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg;
+package com.android.internal.pm.pkg;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
+import com.android.server.pm.pkg.AndroidPackageSplit;
+
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -94,8 +96,8 @@ public class AndroidPackageSplitImpl implements AndroidPackageSplit {
if (this == o) return true;
if (!(o instanceof AndroidPackageSplitImpl)) return false;
AndroidPackageSplitImpl that = (AndroidPackageSplitImpl) o;
- var fieldsEqual = mRevisionCode == that.mRevisionCode && mFlags == that.mFlags && Objects.equals(
- mName, that.mName) && Objects.equals(mPath, that.mPath)
+ var fieldsEqual = mRevisionCode == that.mRevisionCode && mFlags == that.mFlags
+ && Objects.equals(mName, that.mName) && Objects.equals(mPath, that.mPath)
&& Objects.equals(mClassLoaderName, that.mClassLoaderName);
if (!fieldsEqual) return false;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index 099c67654250..4ed361f24439 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.parsing;
+package com.android.internal.pm.pkg.parsing;
import android.annotation.CallSuper;
import android.annotation.NonNull;
@@ -32,6 +32,7 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.R;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
import com.android.internal.pm.pkg.component.ParsedAttribution;
@@ -43,7 +44,6 @@ 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.server.pm.parsing.pkg.ParsedPackage;
import java.security.PublicKey;
import java.util.List;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageHidden.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageHidden.java
index 9c1c9ac9efcd..5758fd7cc579 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageHidden.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageHidden.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.parsing;
+package com.android.internal.pm.pkg.parsing;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 942aa8c14fe8..dd310dc3922a 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -175,6 +175,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
private static final long NAV_BAR_COLOR_DEFAULT_TRANSPARENT = 232195501L;
+ /**
+ * Make app go edge-to-edge by default if the target SDK is
+ * {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} or above.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private static final long EDGE_TO_EDGE_BY_DEFAULT = 309578419;
+
private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES |
(1 << FEATURE_CUSTOM_TITLE) |
(1 << FEATURE_CONTENT_TRANSITIONS) |
@@ -387,7 +395,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mAllowFloatingWindowsFillScreen = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowFloatingWindowsFillScreen);
mDefaultEdgeToEdge =
- context.getApplicationInfo().targetSdkVersion >= DEFAULT_EDGE_TO_EDGE_SDK_VERSION;
+ context.getApplicationInfo().targetSdkVersion >= DEFAULT_EDGE_TO_EDGE_SDK_VERSION
+ || (CompatChanges.isChangeEnabled(EDGE_TO_EDGE_BY_DEFAULT)
+ && Flags.edgeToEdgeByDefault());
if (mDefaultEdgeToEdge) {
mDecorFitsSystemWindows = false;
}
@@ -2558,11 +2568,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mNavigationBarColor =
navBarColor == navBarDefaultColor
+ && !mDefaultEdgeToEdge
&& !(CompatChanges.isChangeEnabled(NAV_BAR_COLOR_DEFAULT_TRANSPARENT)
&& Flags.navBarTransparentByDefault())
&& !context.getResources().getBoolean(
R.bool.config_navBarDefaultTransparent)
- && !mDefaultEdgeToEdge
? navBarCompatibleColor
: navBarColor;
diff --git a/core/java/com/android/server/pm/OWNERS b/core/java/com/android/server/pm/OWNERS
new file mode 100644
index 000000000000..6ef34e2e5d4b
--- /dev/null
+++ b/core/java/com/android/server/pm/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 36137
+
+file:/PACKAGE_MANAGER_OWNERS
+
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java
index 99819c82c5df..4e4f26cd6ad6 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -58,7 +58,6 @@ 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.server.pm.pkg.parsing.ParsingPackageUtils;
import java.security.PublicKey;
import java.util.List;
@@ -691,7 +690,7 @@ public interface AndroidPackage {
/**
* The names of packages to adopt ownership of permissions from, parsed under {@link
- * ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
+ * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
*
* @see R.styleable#AndroidManifestOriginalPackage_name
* @hide
@@ -796,7 +795,7 @@ public interface AndroidPackage {
/**
* For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
- * ParsingPackageUtils#TAG_KEY_SETS}.
+ * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_KEY_SETS}.
*
* @see R.styleable#AndroidManifestKeySet
* @see R.styleable#AndroidManifestPublicKey
@@ -905,7 +904,7 @@ public interface AndroidPackage {
* For system use to migrate from an old package name to a new one, moving over data if
* available.
*
- * @see R.styleable#AndroidManifestOriginalPackage}
+ * @see R.styleable#AndroidManifestOriginalPackage
* @hide
*/
@NonNull
@@ -1267,7 +1266,7 @@ public interface AndroidPackage {
/**
* For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
- * ParsingPackageUtils#TAG_KEY_SETS}.
+ * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_KEY_SETS}.
*
* @see R.styleable#AndroidManifestUpgradeKeySet
* @hide
@@ -1417,6 +1416,7 @@ public interface AndroidPackage {
* @see ApplicationInfo#FLAG_IS_GAME
* @see R.styleable#AndroidManifestApplication_isGame
* @hide
+ * @deprecated
*/
@Deprecated
boolean isGame();
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackageSplit.java b/core/java/com/android/server/pm/pkg/AndroidPackageSplit.java
index 9024c27ebecb..9024c27ebecb 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackageSplit.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackageSplit.java
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 262f5e8e761e..239c6260800b 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -81,7 +81,8 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
deviceInfo.getId(), deviceInfo.getGeneration(),
deviceInfo.getControllerNumber(), nameObj.get(),
static_cast<int32_t>(ident.vendor),
- static_cast<int32_t>(ident.product), descriptorObj.get(),
+ static_cast<int32_t>(ident.product),
+ static_cast<int32_t>(ident.bus), descriptorObj.get(),
deviceInfo.isExternal(), deviceInfo.getSources(),
deviceInfo.getKeyboardType(), kcmObj.get(),
keyboardLanguageTagObj.get(), keyboardLayoutTypeObj.get(),
@@ -111,7 +112,7 @@ int register_android_view_InputDevice(JNIEnv* env)
gInputDeviceClassInfo.clazz = MakeGlobalRefOrDie(env, gInputDeviceClassInfo.clazz);
gInputDeviceClassInfo.ctor = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>",
- "(IIILjava/lang/String;IILjava/lang/"
+ "(IIILjava/lang/String;IIILjava/lang/"
"String;ZIILandroid/view/KeyCharacterMap;Ljava/"
"lang/String;Ljava/lang/String;ZZZZZIII)V");
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index eed186ad3702..73a7e4296a57 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -6350,4 +6350,20 @@ ul.</string>
<string name="keyboard_layout_notification_multiple_selected_title">Physical keyboards configured</string>
<!-- Notification message when multiple keyboards with selected layouts have been connected the first time simultaneously [CHAR LIMIT=NOTIF_BODY] -->
<string name="keyboard_layout_notification_multiple_selected_message">Tap to view keyboards</string>
+
+ <!-- Private profile label on a screen. This can be used as a tab label for this profile in tabbed views and can be used to represent the profile in sharing surfaces, etc. [CHAR LIMIT=20] -->
+ <string name="profile_label_private">Private</string>
+ <!-- Clone profile label on a screen. This can be used as a tab label for this profile in tabbed views and can be used to represent the profile in sharing surfaces, etc. [CHAR LIMIT=20] -->
+ <string name="profile_label_clone">Clone</string>
+ <!-- Work profile label on a screen. This can be used as a tab label for this profile in tabbed views and can be used to represent the profile in sharing surfaces, etc. [CHAR LIMIT=20] -->
+ <string name="profile_label_work">Work</string>
+ <!-- 2nd Work profile label on a screen in case a device has more than one work profiles. This can be used as a tab label for this profile in tabbed views and can be used to represent the profile in sharing surfaces, etc. [CHAR LIMIT=20] -->
+ <string name="profile_label_work_2">Work 2</string>
+ <!-- 3rd Work profile label on a screen in case a device has more than two work profiles. This can be used as a tab label for this profile in tabbed views and can be used to represent the profile in sharing surfaces, etc. [CHAR LIMIT=20] -->
+ <string name="profile_label_work_3">Work 3</string>
+ <!-- Test profile label on a screen. This can be used as a tab label for this profile in tabbed views and can be used to represent the profile in sharing surfaces, etc. [CHAR LIMIT=20] -->
+ <string name="profile_label_test">Test</string>
+ <!-- Communal profile label on a screen. This can be used as a tab label for this profile in tabbed views and can be used to represent the profile in sharing surfaces, etc. [CHAR LIMIT=20] -->
+ <string name="profile_label_communal">Communal</string>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 24b39bc1225e..38f1f6756d17 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1086,6 +1086,13 @@
<java-symbol type="string" name="managed_profile_label_badge_3" />
<java-symbol type="string" name="clone_profile_label_badge" />
<java-symbol type="string" name="private_profile_label_badge" />
+ <java-symbol type="string" name="profile_label_private" />
+ <java-symbol type="string" name="profile_label_clone" />
+ <java-symbol type="string" name="profile_label_work" />
+ <java-symbol type="string" name="profile_label_work_2" />
+ <java-symbol type="string" name="profile_label_work_3" />
+ <java-symbol type="string" name="profile_label_test" />
+ <java-symbol type="string" name="profile_label_communal" />
<java-symbol type="string" name="mediasize_unknown_portrait" />
<java-symbol type="string" name="mediasize_unknown_landscape" />
<java-symbol type="string" name="mediasize_iso_a0" />
diff --git a/core/tests/timetests/TEST_MAPPING b/core/tests/timetests/TEST_MAPPING
index 57480445a7b0..0796d5af36d0 100644
--- a/core/tests/timetests/TEST_MAPPING
+++ b/core/tests/timetests/TEST_MAPPING
@@ -1,6 +1,5 @@
{
- // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
- "postsubmit": [
+ "presubmit": [
{
"name": "FrameworksTimeCoreTests"
}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index f19acbe023b8..d36ac3914ff3 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -991,12 +991,6 @@
"group": "WM_DEBUG_WINDOW_INSETS",
"at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
},
- "-1176488860": {
- "message": "SURFACE isSecure=%b: %s",
- "level": "INFO",
- "group": "WM_SHOW_TRANSACTIONS",
- "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
- },
"-1164930508": {
"message": "Moving to RESUMED: %s (starting new instance) callers=%s",
"level": "VERBOSE",
@@ -3277,6 +3271,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "810599500": {
+ "message": "SURFACE isSecure=%b: %s",
+ "level": "INFO",
+ "group": "WM_SHOW_TRANSACTIONS",
+ "at": "com\/android\/server\/wm\/WindowState.java"
+ },
"829434921": {
"message": "Draw state now committed in %s",
"level": "VERBOSE",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 3e113276027e..e74e578dc213 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -788,7 +788,7 @@ public class BubbleController implements ConfigurationChangeListener,
mLayerView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
if (!windowInsets.equals(mWindowInsets) && mLayerView != null) {
mWindowInsets = windowInsets;
- mBubblePositioner.update();
+ mBubblePositioner.update(DeviceConfig.create(mContext, mWindowManager));
mLayerView.onDisplaySizeChanged();
}
return windowInsets;
@@ -798,7 +798,7 @@ public class BubbleController implements ConfigurationChangeListener,
mStackView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
if (!windowInsets.equals(mWindowInsets) && mStackView != null) {
mWindowInsets = windowInsets;
- mBubblePositioner.update();
+ mBubblePositioner.update(DeviceConfig.create(mContext, mWindowManager));
mStackView.onDisplaySizeChanged();
}
return windowInsets;
@@ -980,7 +980,7 @@ public class BubbleController implements ConfigurationChangeListener,
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mBubblePositioner != null) {
- mBubblePositioner.update();
+ mBubblePositioner.update(DeviceConfig.create(mContext, mWindowManager));
}
if (mStackView != null && newConfig != null) {
if (newConfig.densityDpi != mDensityDpi
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 09ae84a50328..1efd9df3a1d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -16,10 +16,7 @@
package com.android.wm.shell.bubbles;
-import static android.view.View.LAYOUT_DIRECTION_RTL;
-
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Point;
@@ -28,9 +25,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import android.view.Surface;
-import android.view.WindowInsets;
import android.view.WindowManager;
-import android.view.WindowMetrics;
import androidx.annotation.VisibleForTesting;
@@ -68,15 +63,12 @@ public class BubblePositioner {
private static final float EXPANDED_VIEW_BUBBLE_BAR_LANDSCAPE_WIDTH_PERCENT = 0.4f;
private Context mContext;
- private WindowManager mWindowManager;
+ private DeviceConfig mDeviceConfig;
private Rect mScreenRect;
private @Surface.Rotation int mRotation = Surface.ROTATION_0;
private Insets mInsets;
private boolean mImeVisible;
private int mImeHeight;
- private boolean mIsLargeScreen;
- private boolean mIsSmallTablet;
-
private Rect mPositionRect;
private int mDefaultMaxBubbles;
private int mMaxBubbles;
@@ -110,44 +102,27 @@ public class BubblePositioner {
public BubblePositioner(Context context, WindowManager windowManager) {
mContext = context;
- mWindowManager = windowManager;
- update();
+ mDeviceConfig = DeviceConfig.create(context, windowManager);
+ update(mDeviceConfig);
}
/**
* Available space and inset information. Call this when config changes
* occur or when added to a window.
*/
- public void update() {
- WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
- if (windowMetrics == null) {
- return;
- }
- WindowInsets metricInsets = windowMetrics.getWindowInsets();
- Insets insets = metricInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
- | WindowInsets.Type.statusBars()
- | WindowInsets.Type.displayCutout());
-
- final Rect bounds = windowMetrics.getBounds();
- Configuration config = mContext.getResources().getConfiguration();
- mIsLargeScreen = config.smallestScreenWidthDp >= 600;
- if (mIsLargeScreen) {
- float largestEdgeDp = Math.max(config.screenWidthDp, config.screenHeightDp);
- mIsSmallTablet = largestEdgeDp < 960;
- } else {
- mIsSmallTablet = false;
- }
+ public void update(DeviceConfig deviceConfig) {
+ mDeviceConfig = deviceConfig;
if (BubbleDebugConfig.DEBUG_POSITIONER) {
Log.w(TAG, "update positioner:"
+ " rotation: " + mRotation
- + " insets: " + insets
- + " isLargeScreen: " + mIsLargeScreen
- + " isSmallTablet: " + mIsSmallTablet
+ + " insets: " + deviceConfig.getInsets()
+ + " isLargeScreen: " + deviceConfig.isLargeScreen()
+ + " isSmallTablet: " + deviceConfig.isSmallTablet()
+ " showingInBubbleBar: " + mShowingInBubbleBar
- + " bounds: " + bounds);
+ + " bounds: " + deviceConfig.getWindowBounds());
}
- updateInternal(mRotation, insets, bounds);
+ updateInternal(mRotation, deviceConfig.getInsets(), deviceConfig.getWindowBounds());
}
@VisibleForTesting
@@ -175,15 +150,15 @@ public class BubblePositioner {
mExpandedViewLargeScreenWidth = isLandscape()
? (int) (bounds.width() * EXPANDED_VIEW_BUBBLE_BAR_LANDSCAPE_WIDTH_PERCENT)
: (int) (bounds.width() * EXPANDED_VIEW_BUBBLE_BAR_PORTRAIT_WIDTH_PERCENT);
- } else if (mIsSmallTablet) {
+ } else if (mDeviceConfig.isSmallTablet()) {
mExpandedViewLargeScreenWidth = (int) (bounds.width()
* EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT);
} else {
mExpandedViewLargeScreenWidth =
res.getDimensionPixelSize(R.dimen.bubble_expanded_view_largescreen_width);
}
- if (mIsLargeScreen) {
- if (mIsSmallTablet) {
+ if (mDeviceConfig.isLargeScreen()) {
+ if (mDeviceConfig.isSmallTablet()) {
final int centeredInset = (bounds.width() - mExpandedViewLargeScreenWidth) / 2;
mExpandedViewLargeScreenInsetClosestEdge = centeredInset;
mExpandedViewLargeScreenInsetFurthestEdge = centeredInset;
@@ -264,13 +239,12 @@ public class BubblePositioner {
/** @return whether the device is in landscape orientation. */
public boolean isLandscape() {
- return mContext.getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_LANDSCAPE;
+ return mDeviceConfig.isLandscape();
}
/** @return whether the screen is considered large. */
public boolean isLargeScreen() {
- return mIsLargeScreen;
+ return mDeviceConfig.isLargeScreen();
}
/**
@@ -281,7 +255,7 @@ public class BubblePositioner {
* to the left or right side.
*/
public boolean showBubblesVertically() {
- return isLandscape() || mIsLargeScreen;
+ return isLandscape() || mDeviceConfig.isLargeScreen();
}
/** Size of the bubble. */
@@ -334,7 +308,7 @@ public class BubblePositioner {
}
private int getExpandedViewLargeScreenInsetFurthestEdge(boolean isOverflow) {
- if (isOverflow && mIsLargeScreen) {
+ if (isOverflow && mDeviceConfig.isLargeScreen()) {
return mScreenRect.width()
- mExpandedViewLargeScreenInsetClosestEdge
- mOverflowWidth;
@@ -358,7 +332,7 @@ public class BubblePositioner {
final int pointerTotalHeight = getPointerSize();
final int expandedViewLargeScreenInsetFurthestEdge =
getExpandedViewLargeScreenInsetFurthestEdge(isOverflow);
- if (mIsLargeScreen) {
+ if (mDeviceConfig.isLargeScreen()) {
// Note:
// If we're in portrait OR if we're a small tablet, then the two insets values will
// be equal. If we're landscape and a large tablet, the two values will be different.
@@ -439,12 +413,12 @@ public class BubblePositioner {
*/
public float getExpandedViewHeight(BubbleViewProvider bubble) {
boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
- if (isOverflow && showBubblesVertically() && !mIsLargeScreen) {
+ if (isOverflow && showBubblesVertically() && !mDeviceConfig.isLargeScreen()) {
// overflow in landscape on phone is max
return MAX_HEIGHT;
}
- if (mIsLargeScreen && !mIsSmallTablet && !isOverflow) {
+ if (mDeviceConfig.isLargeScreen() && !mDeviceConfig.isSmallTablet() && !isOverflow) {
// the expanded view height on large tablets is calculated based on the shortest screen
// size and is the same in both portrait and landscape
int maxVerticalInset = Math.max(mInsets.top, mInsets.bottom);
@@ -529,11 +503,9 @@ public class BubblePositioner {
*/
public PointF getExpandedBubbleXY(int index, BubbleStackView.StackViewState state) {
boolean showBubblesVertically = showBubblesVertically();
- boolean isRtl = mContext.getResources().getConfiguration().getLayoutDirection()
- == LAYOUT_DIRECTION_RTL;
int onScreenIndex;
- if (showBubblesVertically || !isRtl) {
+ if (showBubblesVertically || !mDeviceConfig.isRtl()) {
onScreenIndex = index;
} else {
// If bubbles are shown horizontally, check if RTL language is used.
@@ -554,10 +526,10 @@ public class BubblePositioner {
if (showBubblesVertically) {
int inset = mExpandedViewLargeScreenInsetClosestEdge;
y = rowStart + positionInRow;
- int left = mIsLargeScreen
+ int left = mDeviceConfig.isLargeScreen()
? inset - mExpandedViewPadding - mBubbleSize
: mPositionRect.left;
- int right = mIsLargeScreen
+ int right = mDeviceConfig.isLargeScreen()
? mPositionRect.right - inset + mExpandedViewPadding
: mPositionRect.right - mBubbleSize;
x = state.onLeft
@@ -693,13 +665,10 @@ public class BubblePositioner {
* @param isAppBubble whether this start position is for an app bubble or not.
*/
public PointF getDefaultStartPosition(boolean isAppBubble) {
- final int layoutDirection = mContext.getResources().getConfiguration().getLayoutDirection();
// Normal bubbles start on the left if we're in LTR, right otherwise.
// TODO (b/294284894): update language around "app bubble" here
// App bubbles start on the right in RTL, left otherwise.
- final boolean startOnLeft = isAppBubble
- ? layoutDirection == LAYOUT_DIRECTION_RTL
- : layoutDirection != LAYOUT_DIRECTION_RTL;
+ final boolean startOnLeft = isAppBubble ? mDeviceConfig.isRtl() : !mDeviceConfig.isRtl();
return getStartPosition(startOnLeft ? StackPinnedEdge.LEFT : StackPinnedEdge.RIGHT);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 2cee675e83be..8f904c42d247 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -61,6 +61,7 @@ import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewPropertyAnimator;
import android.view.ViewTreeObserver;
+import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -1001,7 +1002,8 @@ public class BubbleStackView extends FrameLayout
mOrientationChangedListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
- mPositioner.update();
+ mPositioner.update(DeviceConfig.create(mContext, mContext.getSystemService(
+ WindowManager.class)));
onDisplaySizeChanged();
mExpandedAnimationController.updateResources();
mStackAnimationController.updateResources();
@@ -1522,7 +1524,8 @@ public class BubbleStackView extends FrameLayout
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mPositioner.update();
+ WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+ mPositioner.update(DeviceConfig.create(mContext, Objects.requireNonNull(windowManager)));
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DeviceConfig.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DeviceConfig.kt
new file mode 100644
index 000000000000..929330918174
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DeviceConfig.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.bubbles
+
+import android.content.Context
+import android.content.res.Configuration
+import android.content.res.Configuration.ORIENTATION_LANDSCAPE
+import android.graphics.Insets
+import android.graphics.Rect
+import android.view.View.LAYOUT_DIRECTION_RTL
+import android.view.WindowInsets
+import android.view.WindowManager
+import kotlin.math.max
+
+/** Contains device configuration used for positioning bubbles on the screen. */
+data class DeviceConfig(
+ val isLargeScreen: Boolean,
+ val isSmallTablet: Boolean,
+ val isLandscape: Boolean,
+ val isRtl: Boolean,
+ val windowBounds: Rect,
+ val insets: Insets
+) {
+ companion object {
+
+ private const val LARGE_SCREEN_MIN_EDGE_DP = 600
+ private const val SMALL_TABLET_MAX_EDGE_DP = 960
+
+ @JvmStatic
+ fun create(context: Context, windowManager: WindowManager): DeviceConfig {
+ val windowMetrics = windowManager.currentWindowMetrics
+ val metricInsets = windowMetrics.windowInsets
+ val insets = metricInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
+ or WindowInsets.Type.statusBars()
+ or WindowInsets.Type.displayCutout())
+ val windowBounds = windowMetrics.bounds
+ val config: Configuration = context.resources.configuration
+ val isLargeScreen = config.smallestScreenWidthDp >= LARGE_SCREEN_MIN_EDGE_DP
+ val largestEdgeDp = max(config.screenWidthDp, config.screenHeightDp)
+ val isSmallTablet = isLargeScreen && largestEdgeDp < SMALL_TABLET_MAX_EDGE_DP
+ val isLandscape = context.resources.configuration.orientation == ORIENTATION_LANDSCAPE
+ val isRtl = context.resources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL
+ return DeviceConfig(
+ isLargeScreen = isLargeScreen,
+ isSmallTablet = isSmallTablet,
+ isLandscape = isLandscape,
+ isRtl = isRtl,
+ windowBounds = windowBounds,
+ insets = insets
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index e788341df5f8..92cb436528cc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -28,13 +28,16 @@ import android.graphics.drawable.ColorDrawable;
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewTreeObserver;
+import android.view.WindowManager;
import android.widget.FrameLayout;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
+import com.android.wm.shell.bubbles.DeviceConfig;
+import java.util.Objects;
import java.util.function.Consumer;
import kotlin.Unit;
@@ -104,7 +107,8 @@ public class BubbleBarLayerView extends FrameLayout
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mPositioner.update();
+ WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+ mPositioner.update(DeviceConfig.create(mContext, Objects.requireNonNull(windowManager)));
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 4a9ea6fed73f..144555dd70c3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -21,7 +21,6 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
-import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.app.WindowConfiguration.WindowingMode
import android.content.Context
@@ -321,24 +320,10 @@ class DesktopTasksController(
}
/** Move a task with given `taskId` to fullscreen */
- fun moveToFullscreen(taskId: Int) {
- shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveToFullscreen(task) }
- }
-
- /** Move a task to fullscreen */
- fun moveToFullscreen(task: RunningTaskInfo) {
- KtProtoLog.v(
- WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: moveToFullscreen taskId=%d",
- task.taskId
- )
-
- val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(wct, task)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
- } else {
- shellTaskOrganizer.applyTransaction(wct)
+ fun moveToFullscreen(taskId: Int, windowDecor: DesktopModeWindowDecoration) {
+ shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task ->
+ windowDecor.incrementRelayoutBlock()
+ moveToFullscreenWithAnimation(task, task.positionInParent)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index dd6ca8da56eb..03006f920072 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -428,7 +428,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
if (isTaskInSplitScreen(mTaskId)) {
mSplitScreenController.moveTaskToFullscreen(mTaskId);
} else {
- mDesktopTasksController.ifPresent(c -> c.moveToFullscreen(mTaskId));
+ mDesktopTasksController.ifPresent(c ->
+ c.moveToFullscreen(mTaskId, mWindowDecorByTaskId.get(mTaskId)));
}
} else if (id == R.id.split_screen_button) {
decoration.closeHandleMenu();
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt
index 744e8c2eb06f..181474fa0590 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt
@@ -57,25 +57,18 @@ class LetterboxRule(
resetLetterboxStyle()
_letterboxStyle = mapLetterboxStyle()
val isLetterboxEducationEnabled = _letterboxStyle.getValue("Is education enabled")
- var hasLetterboxEducationStateChanged = false
if ("$withLetterboxEducationEnabled" != isLetterboxEducationEnabled) {
- hasLetterboxEducationStateChanged = true
execAdb("wm set-letterbox-style --isEducationEnabled " + withLetterboxEducationEnabled)
}
- return try {
- object : Statement() {
- @Throws(Throwable::class)
- override fun evaluate() {
+ return object : Statement() {
+ @Throws(Throwable::class)
+ override fun evaluate() {
+ try {
base!!.evaluate()
+ } finally {
+ resetLetterboxStyle()
}
}
- } finally {
- if (hasLetterboxEducationStateChanged) {
- execAdb(
- "wm set-letterbox-style --isEducationEnabled " + isLetterboxEducationEnabled
- )
- }
- resetLetterboxStyle()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
index 89ecc29d977b..6429b00a2a58 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
@@ -76,6 +76,17 @@
value="appops set com.android.shell android:mock_location deny"/>
</target_preparer>
+ <!-- Use app crawler to log into Netflix -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command"
+ value="am start -n com.netflix.mediaclient/com.netflix.mediaclient.ui.login.LoginActivity"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="set-option" value="package-name:com.netflix.mediaclient"/>
+ <option name="set-option" value="ui-automator-mode:true"/>
+ <option name="class" value="com.android.csuite.tests.AppCrawlTest" />
+ </test>
+
<!-- Needed for pushing the trace config file -->
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml
index fdda5974d1f9..05f937ab6795 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml
@@ -95,6 +95,8 @@
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/flicker/splitscreen/trace_config/trace_config.textproto
index b55f4ecdb6a4..67316d2d7c0f 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/trace_config/trace_config.textproto
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/trace_config/trace_config.textproto
@@ -63,6 +63,7 @@ data_sources: {
atrace_categories: "sched_process_exit"
atrace_apps: "com.android.server.wm.flicker.testapp"
atrace_apps: "com.android.systemui"
+ atrace_apps: "com.android.wm.shell.flicker.service"
atrace_apps: "com.android.wm.shell.flicker.splitscreen"
atrace_apps: "com.google.android.apps.nexuslauncher"
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index 26c73946c1c6..4bca96b187b5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -192,7 +192,7 @@ public class BubbleDataTest extends ShellTestCase {
mMainExecutor);
mPositioner = new TestableBubblePositioner(mContext,
- mock(WindowManager.class));
+ mContext.getSystemService(WindowManager.class));
mBubbleData = new BubbleData(getContext(), mBubbleLogger, mPositioner, mEducationController,
mMainExecutor);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleOverflowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleOverflowTest.java
index cb29a21e2f5b..f5b0174642d1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleOverflowTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleOverflowTest.java
@@ -53,7 +53,8 @@ public class BubbleOverflowTest extends ShellTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mPositioner = new TestableBubblePositioner(mContext, mock(WindowManager.class));
+ mPositioner = new TestableBubblePositioner(mContext,
+ mContext.getSystemService(WindowManager.class));
when(mBubbleController.getPositioner()).thenReturn(mPositioner);
when(mBubbleController.getStackView()).thenReturn(mock(BubbleStackView.class));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
index 287a97c9b5b0..835ebe2206ad 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
@@ -16,33 +16,17 @@
package com.android.wm.shell.bubbles;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.view.View.LAYOUT_DIRECTION_LTR;
-import static android.view.View.LAYOUT_DIRECTION_RTL;
-
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
import android.content.Intent;
-import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableResources;
-import android.util.DisplayMetrics;
-import android.view.WindowInsets;
import android.view.WindowManager;
-import android.view.WindowMetrics;
import androidx.test.filters.SmallTest;
@@ -52,36 +36,20 @@ import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
/**
* Tests operations and the resulting state managed by {@link BubblePositioner}.
*/
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class BubblePositionerTest extends ShellTestCase {
- private static final int MIN_WIDTH_FOR_TABLET = 600;
-
private BubblePositioner mPositioner;
- private Configuration mConfiguration;
-
- @Mock
- private WindowManager mWindowManager;
- @Mock
- private WindowMetrics mWindowMetrics;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mConfiguration = spy(new Configuration());
- TestableResources testableResources = mContext.getOrCreateTestableResources();
- testableResources.overrideConfiguration(mConfiguration);
-
- mPositioner = new BubblePositioner(mContext, mWindowManager);
+ WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+ mPositioner = new BubblePositioner(mContext, windowManager);
}
@Test
@@ -91,11 +59,11 @@ public class BubblePositionerTest extends ShellTestCase {
Rect availableRect = new Rect(screenBounds);
availableRect.inset(insets);
- new WindowManagerConfig()
+ DeviceConfig deviceConfig = new ConfigBuilder()
.setInsets(insets)
.setScreenBounds(screenBounds)
- .setUpConfig();
- mPositioner.update();
+ .build();
+ mPositioner.update(deviceConfig);
assertThat(mPositioner.getAvailableRect()).isEqualTo(availableRect);
assertThat(mPositioner.isLandscape()).isFalse();
@@ -105,16 +73,16 @@ public class BubblePositionerTest extends ShellTestCase {
@Test
public void testShowBubblesVertically_phonePortrait() {
- new WindowManagerConfig().setOrientation(ORIENTATION_PORTRAIT).setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().build();
+ mPositioner.update(deviceConfig);
assertThat(mPositioner.showBubblesVertically()).isFalse();
}
@Test
public void testShowBubblesVertically_phoneLandscape() {
- new WindowManagerConfig().setOrientation(ORIENTATION_LANDSCAPE).setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().setLandscape().build();
+ mPositioner.update(deviceConfig);
assertThat(mPositioner.isLandscape()).isTrue();
assertThat(mPositioner.showBubblesVertically()).isTrue();
@@ -122,8 +90,8 @@ public class BubblePositionerTest extends ShellTestCase {
@Test
public void testShowBubblesVertically_tablet() {
- new WindowManagerConfig().setLargeScreen().setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().build();
+ mPositioner.update(deviceConfig);
assertThat(mPositioner.showBubblesVertically()).isTrue();
}
@@ -131,8 +99,8 @@ public class BubblePositionerTest extends ShellTestCase {
/** If a resting position hasn't been set, calling it will return the default position. */
@Test
public void testGetRestingPosition_returnsDefaultPosition() {
- new WindowManagerConfig().setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().build();
+ mPositioner.update(deviceConfig);
PointF restingPosition = mPositioner.getRestingPosition();
PointF defaultPosition = mPositioner.getDefaultStartPosition();
@@ -143,8 +111,8 @@ public class BubblePositionerTest extends ShellTestCase {
/** If a resting position has been set, it'll return that instead of the default position. */
@Test
public void testGetRestingPosition_returnsRestingPosition() {
- new WindowManagerConfig().setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().build();
+ mPositioner.update(deviceConfig);
PointF restingPosition = new PointF(100, 100);
mPositioner.setRestingPosition(restingPosition);
@@ -155,8 +123,8 @@ public class BubblePositionerTest extends ShellTestCase {
/** Test that the default resting position on phone is in upper left. */
@Test
public void testGetRestingPosition_bubble_onPhone() {
- new WindowManagerConfig().setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().build();
+ mPositioner.update(deviceConfig);
RectF allowableStackRegion =
mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
@@ -168,8 +136,8 @@ public class BubblePositionerTest extends ShellTestCase {
@Test
public void testGetRestingPosition_bubble_onPhone_RTL() {
- new WindowManagerConfig().setLayoutDirection(LAYOUT_DIRECTION_RTL).setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().setRtl().build();
+ mPositioner.update(deviceConfig);
RectF allowableStackRegion =
mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
@@ -182,8 +150,8 @@ public class BubblePositionerTest extends ShellTestCase {
/** Test that the default resting position on tablet is middle left. */
@Test
public void testGetRestingPosition_chatBubble_onTablet() {
- new WindowManagerConfig().setLargeScreen().setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().build();
+ mPositioner.update(deviceConfig);
RectF allowableStackRegion =
mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
@@ -195,9 +163,8 @@ public class BubblePositionerTest extends ShellTestCase {
@Test
public void testGetRestingPosition_chatBubble_onTablet_RTL() {
- new WindowManagerConfig().setLargeScreen().setLayoutDirection(
- LAYOUT_DIRECTION_RTL).setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build();
+ mPositioner.update(deviceConfig);
RectF allowableStackRegion =
mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
@@ -210,8 +177,8 @@ public class BubblePositionerTest extends ShellTestCase {
/** Test that the default resting position on tablet is middle right. */
@Test
public void testGetDefaultPosition_appBubble_onTablet() {
- new WindowManagerConfig().setLargeScreen().setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().build();
+ mPositioner.update(deviceConfig);
RectF allowableStackRegion =
mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
@@ -223,9 +190,8 @@ public class BubblePositionerTest extends ShellTestCase {
@Test
public void testGetRestingPosition_appBubble_onTablet_RTL() {
- new WindowManagerConfig().setLargeScreen().setLayoutDirection(
- LAYOUT_DIRECTION_RTL).setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build();
+ mPositioner.update(deviceConfig);
RectF allowableStackRegion =
mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
@@ -237,9 +203,8 @@ public class BubblePositionerTest extends ShellTestCase {
@Test
public void testHasUserModifiedDefaultPosition_false() {
- new WindowManagerConfig().setLargeScreen().setLayoutDirection(
- LAYOUT_DIRECTION_RTL).setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build();
+ mPositioner.update(deviceConfig);
assertThat(mPositioner.hasUserModifiedDefaultPosition()).isFalse();
@@ -250,9 +215,8 @@ public class BubblePositionerTest extends ShellTestCase {
@Test
public void testHasUserModifiedDefaultPosition_true() {
- new WindowManagerConfig().setLargeScreen().setLayoutDirection(
- LAYOUT_DIRECTION_RTL).setUpConfig();
- mPositioner.update();
+ DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build();
+ mPositioner.update(deviceConfig);
assertThat(mPositioner.hasUserModifiedDefaultPosition()).isFalse();
@@ -266,12 +230,12 @@ public class BubblePositionerTest extends ShellTestCase {
Insets insets = Insets.of(10, 20, 5, 15);
Rect screenBounds = new Rect(0, 0, 1800, 2600);
- new WindowManagerConfig()
+ DeviceConfig deviceConfig = new ConfigBuilder()
.setLargeScreen()
.setInsets(insets)
.setScreenBounds(screenBounds)
- .setUpConfig();
- mPositioner.update();
+ .build();
+ mPositioner.update(deviceConfig);
Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
@@ -311,58 +275,47 @@ public class BubblePositionerTest extends ShellTestCase {
* Sets up window manager to return config values based on what you need for the test.
* By default it sets up a portrait phone without any insets.
*/
- private class WindowManagerConfig {
+ private static class ConfigBuilder {
private Rect mScreenBounds = new Rect(0, 0, 1000, 2000);
private boolean mIsLargeScreen = false;
- private int mOrientation = ORIENTATION_PORTRAIT;
- private int mLayoutDirection = LAYOUT_DIRECTION_LTR;
+ private boolean mIsSmallTablet = false;
+ private boolean mIsLandscape = false;
+ private boolean mIsRtl = false;
private Insets mInsets = Insets.of(0, 0, 0, 0);
- public WindowManagerConfig setScreenBounds(Rect screenBounds) {
+ public ConfigBuilder setScreenBounds(Rect screenBounds) {
mScreenBounds = screenBounds;
return this;
}
- public WindowManagerConfig setLargeScreen() {
+ public ConfigBuilder setLargeScreen() {
mIsLargeScreen = true;
return this;
}
- public WindowManagerConfig setOrientation(int orientation) {
- mOrientation = orientation;
+ public ConfigBuilder setSmallTablet() {
+ mIsSmallTablet = true;
return this;
}
- public WindowManagerConfig setLayoutDirection(int layoutDirection) {
- mLayoutDirection = layoutDirection;
+ public ConfigBuilder setLandscape() {
+ mIsLandscape = true;
return this;
}
- public WindowManagerConfig setInsets(Insets insets) {
- mInsets = insets;
+ public ConfigBuilder setRtl() {
+ mIsRtl = true;
return this;
}
- public void setUpConfig() {
- mConfiguration.smallestScreenWidthDp = mIsLargeScreen
- ? MIN_WIDTH_FOR_TABLET
- : MIN_WIDTH_FOR_TABLET - 1;
- mConfiguration.orientation = mOrientation;
- mConfiguration.screenWidthDp = pxToDp(mScreenBounds.width());
- mConfiguration.screenHeightDp = pxToDp(mScreenBounds.height());
-
- when(mConfiguration.getLayoutDirection()).thenReturn(mLayoutDirection);
- WindowInsets windowInsets = mock(WindowInsets.class);
- when(windowInsets.getInsetsIgnoringVisibility(anyInt())).thenReturn(mInsets);
- when(mWindowMetrics.getWindowInsets()).thenReturn(windowInsets);
- when(mWindowMetrics.getBounds()).thenReturn(mScreenBounds);
- when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
+ public ConfigBuilder setInsets(Insets insets) {
+ mInsets = insets;
+ return this;
}
- private int pxToDp(float px) {
- int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
- float dp = px / ((float) dpi / DisplayMetrics.DENSITY_DEFAULT);
- return (int) dp;
+ private DeviceConfig build() {
+ return new DeviceConfig(mIsLargeScreen, mIsSmallTablet, mIsLandscape, mIsRtl,
+ mScreenBounds, mInsets);
}
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java
index 44ff35466ae2..c4b9c9ba43f1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java
@@ -55,8 +55,6 @@ public class BubblesNavBarMotionEventHandlerTest extends ShellTestCase {
private BubblesNavBarMotionEventHandler mMotionEventHandler;
@Mock
- private WindowManager mWindowManager;
- @Mock
private Runnable mInterceptTouchRunnable;
@Mock
private MotionEventListener mMotionEventListener;
@@ -66,7 +64,7 @@ public class BubblesNavBarMotionEventHandlerTest extends ShellTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
TestableBubblePositioner positioner = new TestableBubblePositioner(getContext(),
- mWindowManager);
+ getContext().getSystemService(WindowManager.class));
mMotionEventHandler = new BubblesNavBarMotionEventHandler(getContext(), positioner,
mInterceptTouchRunnable, mMotionEventListener);
mMotionEventTime = SystemClock.uptimeMillis();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
index 335222e98c6c..6403e794a33e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -66,7 +66,8 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
public void setUp() throws Exception {
super.setUp();
- mPositioner = new BubblePositioner(getContext(), mock(WindowManager.class));
+ mPositioner = new BubblePositioner(getContext(),
+ getContext().getSystemService(WindowManager.class));
mPositioner.updateInternal(Configuration.ORIENTATION_PORTRAIT,
Insets.of(0, 0, 0, 0),
new Rect(0, 0, mDisplayWidth, mDisplayHeight));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java
index 991913afbb90..f6609872852f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java
@@ -50,9 +50,6 @@ public class ExpandedViewAnimationControllerTest extends ShellTestCase {
private ExpandedViewAnimationController mController;
@Mock
- private WindowManager mWindowManager;
-
- @Mock
private BubbleExpandedView mMockExpandedView;
@Before
@@ -60,7 +57,7 @@ public class ExpandedViewAnimationControllerTest extends ShellTestCase {
MockitoAnnotations.initMocks(this);
TestableBubblePositioner positioner = new TestableBubblePositioner(getContext(),
- mWindowManager);
+ getContext().getSystemService(WindowManager.class));
mController = new ExpandedViewAnimationControllerImpl(getContext(), positioner);
mController.setExpandedView(mMockExpandedView);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java
index 31fafcaab7cc..0c22908be9eb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java
@@ -313,7 +313,8 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase
bubbleCountSupplier,
onBubbleAnimatedOutAction,
onStackAnimationFinished,
- new TestableBubblePositioner(mContext, mock(WindowManager.class)));
+ new TestableBubblePositioner(mContext,
+ mContext.getSystemService(WindowManager.class)));
}
@Override
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index fde6acb9bfe5..94c862bd7a4f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -63,6 +63,7 @@ import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.OneShotRemoteHandler
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS
+import com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_DESKTOP_MODE
import com.android.wm.shell.transition.Transitions.TransitionHandler
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
import com.google.common.truth.Truth.assertThat
@@ -392,8 +393,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun moveToFullscreen_displayFullscreen_windowingModeSetToUndefined() {
val task = setUpFreeformTask()
task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FULLSCREEN
- controller.moveToFullscreen(task)
- val wct = getLatestWct(type = TRANSIT_CHANGE)
+ controller.moveToFullscreen(task.taskId, desktopModeWindowDecoration)
+ val wct = getLatestExitDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_UNDEFINED)
}
@@ -402,15 +403,15 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun moveToFullscreen_displayFreeform_windowingModeSetToFullscreen() {
val task = setUpFreeformTask()
task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FREEFORM
- controller.moveToFullscreen(task)
- val wct = getLatestWct(type = TRANSIT_CHANGE)
+ controller.moveToFullscreen(task.taskId, desktopModeWindowDecoration)
+ val wct = getLatestExitDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_FULLSCREEN)
}
@Test
fun moveToFullscreen_nonExistentTask_doesNothing() {
- controller.moveToFullscreen(999)
+ controller.moveToFullscreen(999, desktopModeWindowDecoration)
verifyWCTNotExecuted()
}
@@ -419,9 +420,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
val taskDefaultDisplay = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
val taskSecondDisplay = setUpFreeformTask(displayId = SECOND_DISPLAY)
- controller.moveToFullscreen(taskDefaultDisplay)
+ controller.moveToFullscreen(taskDefaultDisplay.taskId, desktopModeWindowDecoration)
- with(getLatestWct(type = TRANSIT_CHANGE)) {
+ with(getLatestExitDesktopWct()) {
assertThat(changes.keys).contains(taskDefaultDisplay.token.asBinder())
assertThat(changes.keys).doesNotContain(taskSecondDisplay.token.asBinder())
}
@@ -808,6 +809,17 @@ class DesktopTasksControllerTest : ShellTestCase() {
return arg.value
}
+ private fun getLatestExitDesktopWct(): WindowContainerTransaction {
+ val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+ if (ENABLE_SHELL_TRANSITIONS) {
+ verify(exitDesktopTransitionHandler)
+ .startTransition(eq(TRANSIT_EXIT_DESKTOP_MODE), arg.capture(), any(), any())
+ } else {
+ verify(shellTaskOrganizer).applyTransaction(arg.capture())
+ }
+ return arg.value
+ }
+
private fun verifyWCTNotExecuted() {
if (ENABLE_SHELL_TRANSITIONS) {
verify(transitions, never()).startTransition(anyInt(), any(), isNull())
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9ae6f8deb98b..1e3234902a45 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -19,6 +19,7 @@ package android.media;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
import static android.content.Context.DEVICE_ID_DEFAULT;
+import static android.media.audio.Flags.autoPublicVolumeApiHardening;
import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API;
import android.Manifest;
@@ -49,6 +50,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.media.AudioAttributes.AttributeSystemUsage;
import android.media.CallbackUtil.ListenerInfo;
import android.media.audiopolicy.AudioPolicy;
@@ -901,6 +903,7 @@ public class AudioManager {
@UnsupportedAppUsage
public AudioManager(Context context) {
setContext(context);
+ initPlatform();
}
private Context getContext() {
@@ -914,6 +917,9 @@ public class AudioManager {
}
private void setContext(Context context) {
+ if (context == null) {
+ return;
+ }
mOriginalContextDeviceId = context.getDeviceId();
mApplicationContext = context.getApplicationContext();
if (mApplicationContext != null) {
@@ -1063,8 +1069,17 @@ public class AudioManager {
* @see #isVolumeFixed()
*/
public void adjustVolume(int direction, @PublicVolumeFlags int flags) {
- MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
- helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
+ if (applyAutoHardening()) {
+ final IAudioService service = getService();
+ try {
+ service.adjustVolume(direction, flags);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
+ helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
+ }
}
/**
@@ -1093,8 +1108,17 @@ public class AudioManager {
*/
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType,
@PublicVolumeFlags int flags) {
- MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
- helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
+ if (applyAutoHardening()) {
+ final IAudioService service = getService();
+ try {
+ service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
+ helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
+ }
}
/** @hide */
@@ -9969,6 +9993,30 @@ public class AudioManager {
}
}
+ //====================================================================
+ // Flag related utilities
+
+ private boolean mIsAutomotive = false;
+
+ private void initPlatform() {
+ try {
+ final Context context = getContext();
+ if (context != null) {
+ mIsAutomotive = context.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error querying system feature for AUTOMOTIVE", e);
+ }
+ }
+
+ private boolean applyAutoHardening() {
+ if (mIsAutomotive && autoPublicVolumeApiHardening()) {
+ return true;
+ }
+ return false;
+ }
+
//---------------------------------------------------------
// Inner classes
//--------------------
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 42400d1d5d82..d14775fa9ad9 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -500,6 +500,10 @@ interface IAudioService {
in String packageName, int uid, int pid, in UserHandle userHandle,
int targetSdkVersion);
+ oneway void adjustVolume(int direction, int flags);
+
+ oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags);
+
boolean isMusicActive(in boolean remotely);
int getDeviceMaskForStream(in int streamType);
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 6031ef70535d..94fce797f5d6 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -122,11 +122,6 @@ cc_library_shared {
"-Wunused",
"-Wunreachable-code",
],
-
- // Workaround Clang LTO crash.
- lto: {
- never: true,
- },
}
cc_library_shared {
diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp
index 8b5b726fd2db..cf5059ceb3c9 100644
--- a/media/jni/audioeffect/Android.bp
+++ b/media/jni/audioeffect/Android.bp
@@ -44,9 +44,4 @@ cc_library_shared {
"-Wunreachable-code",
"-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
-
- // Workaround Clang LTO crash.
- lto: {
- never: true,
- },
}
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
index fd785a45a8ba..b7955603a97a 100644
--- a/mime/java-res/android.mime.types
+++ b/mime/java-res/android.mime.types
@@ -55,6 +55,8 @@
?application/vnd.android.haptics.vibration+xml ahv
?application/vnd.android.ota ota
?application/vnd.apple.mpegurl m3u8
+?application/vnd.apple.pkpass pkpass
+?application/vnd.apple.pkpasses pkpasses
?application/vnd.ms-pki.stl stl
?application/vnd.ms-powerpoint pot
?application/vnd.ms-wpl wpl
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index 8d8254ad4058..daedb1aac298 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -298,14 +298,7 @@ public class InstallInstalling extends Activity {
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
- try {
- session.commit(pendingIntent.getIntentSender());
- } catch (Exception e) {
- Log.e(LOG_TAG, "Cannot install package: ", e);
- launchFailure(PackageInstaller.STATUS_FAILURE,
- PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
- return;
- }
+ session.commit(pendingIntent.getIntentSender());
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else {
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
index 223e99e61204..56796945f015 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
@@ -72,7 +72,8 @@ private fun UserManager.getUserGroups(): List<UserGroup> {
private fun UserManager.showInSettings(userInfo: UserInfo): Int {
val userProperties = getUserProperties(userInfo.userHandle)
- return if (userInfo.isQuietModeEnabled && userProperties.hideInSettingsInQuietMode) {
+ return if (userInfo.isQuietModeEnabled && userProperties.showInQuietMode
+ == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) {
UserProperties.SHOW_IN_SETTINGS_NO
} else {
userProperties.showInSettings
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 1a5acf650cb4..5aa2bfc6441a 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1373,11 +1373,11 @@
<string name="tv_media_transfer_earc_subtitle">Connected via eARC</string>
<!-- TV media output switcher. Title for the default audio output of the device [CHAR LIMIT=NONE] -->
- <string name="tv_media_transfer_default">TV Default</string>
+ <string name="tv_media_transfer_default">TV default</string>
<!-- TV media output switcher. Subtitle for default audio output which is HDMI, e.g. TV dongle [CHAR LIMIT=NONE] -->
- <string name="tv_media_transfer_hdmi">HDMI Output</string>
+ <string name="tv_media_transfer_hdmi">HDMI output</string>
<!-- TV media output switcher. Subtitle for default audio output which is internal speaker, i.e. panel VTs [CHAR LIMIT=NONE] -->
- <string name="tv_media_transfer_internal_speakers">Internal Speakers</string>
+ <string name="tv_media_transfer_internal_speakers">Internal speakers</string>
<!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
<string name="profile_connect_timeout_subtext">Problem connecting. Turn device off &amp; back on</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
index 83c106b18a6b..92db50878a70 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.provider.Settings;
+import android.os.UserManager;
import android.util.ArraySet;
import android.view.accessibility.AccessibilityManager;
@@ -68,4 +69,10 @@ public final class BatteryUtils {
}
return packageNames;
}
+
+ /** Returns true if current user is a work profile user. */
+ public static boolean isWorkProfile(Context context) {
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ return userManager.isManagedProfile() && !userManager.isSystemUser();
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 5dacba5357cd..52b51d7e42e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -413,12 +413,8 @@ public abstract class InfoMediaManager extends MediaManager {
*/
@NonNull
List<MediaDevice> getSelectedMediaDevices() {
- if (TextUtils.isEmpty(mPackageName)) {
- Log.w(TAG, "getSelectedMediaDevices() package name is null or empty!");
- return Collections.emptyList();
- }
+ RoutingSessionInfo info = getRoutingSessionInfo();
- final RoutingSessionInfo info = getRoutingSessionInfo();
if (info == null) {
Log.w(TAG, "getSelectedMediaDevices() cannot find selectable MediaDevice from : "
+ mPackageName);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java
index 3514932d4e8d..02ec90d968b1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java
@@ -48,6 +48,17 @@ public class MediaOutputConstants {
"com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG";
/**
+ * An intent action to launch a media output dialog without any app or playback metadata, which
+ * only controls system routing.
+ *
+ * <p>System routes are those provided by the system, such as built-in speakers, wired headsets,
+ * bluetooth devices, and other outputs that require the app to feed media samples to the
+ * framework.
+ */
+ public static final String ACTION_LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG =
+ "com.android.systemui.action.LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG";
+
+ /**
* An intent action to launch media output broadcast dialog.
*/
public static final String ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG =
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java
index c3e0c0b3b79c..6424352d2c1b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java
@@ -29,6 +29,7 @@ import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.UserManager;
import android.provider.Settings;
import android.view.accessibility.AccessibilityManager;
@@ -40,6 +41,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowAccessibilityManager;
import java.util.Arrays;
@@ -99,6 +101,20 @@ public class BatteryUtilsTest {
.containsExactly(DEFAULT_TTS_PACKAGE, ACCESSIBILITY_PACKAGE);
}
+ @Test
+ public void isWorkProfile_defaultValue_returnFalse() {
+ assertThat(BatteryUtils.isWorkProfile(mContext)).isFalse();
+ }
+
+ @Test
+ public void isWorkProfile_workProfileMode_returnTrue() {
+ final UserManager userManager = mContext.getSystemService(UserManager.class);
+ Shadows.shadowOf(userManager).setManagedProfile(true);
+ Shadows.shadowOf(userManager).setIsSystemUser(false);
+
+ assertThat(BatteryUtils.isWorkProfile(mContext)).isTrue();
+ }
+
private void setTtsPackageName(String defaultTtsPackageName) {
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.TTS_DEFAULT_SYNTH, defaultTtsPackageName);
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e218308758ab..0a71cda4d6dd 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -1044,6 +1044,7 @@
android:exported="true">
<intent-filter android:priority="1">
<action android:name="com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG" />
+ <action android:name="com.android.systemui.action.LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG" />
<action android:name="com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG" />
<action android:name="com.android.systemui.action.DISMISS_MEDIA_OUTPUT_DIALOG" />
</intent-filter>
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a745ab5cbdd9..a9dc145afabd 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -143,8 +143,17 @@ flag {
}
flag {
+ name: "theme_overlay_controller_wakefulness_deprecation"
+ namespace: "systemui"
+ description: "Replacing WakefulnessLifecycle by KeyguardTransitionInteractor in "
+ "ThemOverlayController to mitigate flickering when locking the device"
+ bug: "308676488"
+}
+
+flag {
name: "media_in_scene_container"
namespace: "systemui"
description: "Enable media in the scene container framework"
bug: "296122467"
}
+
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt
index ddc3d3a31e94..1860c9f1656e 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt
@@ -18,8 +18,8 @@ package com.android.systemui.scene
import android.app.AlertDialog
import android.content.Context
+import com.android.systemui.bouncer.ui.composable.BouncerDialogFactory
import com.android.systemui.bouncer.ui.composable.BouncerScene
-import com.android.systemui.bouncer.ui.composable.BouncerSceneDialogFactory
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.shared.model.Scene
@@ -38,8 +38,8 @@ interface BouncerSceneModule {
@Provides
@SysUISingleton
- fun bouncerSceneDialogFactory(@Application context: Context): BouncerSceneDialogFactory {
- return object : BouncerSceneDialogFactory {
+ fun bouncerSceneDialogFactory(@Application context: Context): BouncerDialogFactory {
+ return object : BouncerDialogFactory {
override fun invoke(): AlertDialog {
return SystemUIDialog(context)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
new file mode 100644
index 000000000000..ba80a8deffb7
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -0,0 +1,734 @@
+/*
+ * 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.bouncer.ui.composable
+
+import android.app.AlertDialog
+import android.app.Dialog
+import android.content.DialogInterface
+import androidx.compose.animation.Crossfade
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.snap
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.widthIn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.KeyboardArrowDown
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+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.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.DpOffset
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.times
+import com.android.compose.PlatformButton
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.transitions
+import com.android.compose.modifiers.thenIf
+import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel
+import com.android.systemui.bouncer.ui.helper.BouncerSceneLayout
+import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel
+import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
+import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
+import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
+import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
+import com.android.systemui.common.shared.model.Text.Companion.loadText
+import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.fold.ui.composable.foldPosture
+import com.android.systemui.fold.ui.helper.FoldPosture
+import com.android.systemui.res.R
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.pow
+
+@Composable
+fun BouncerContent(
+ viewModel: BouncerViewModel,
+ dialogFactory: BouncerDialogFactory,
+ modifier: Modifier
+) {
+ val isFullScreenUserSwitcherEnabled = viewModel.isUserSwitcherVisible
+ val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsState()
+ val layout = calculateLayout(isSideBySideSupported = isSideBySideSupported)
+
+ when (layout) {
+ BouncerSceneLayout.STANDARD ->
+ StandardLayout(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ modifier = modifier,
+ )
+ BouncerSceneLayout.SIDE_BY_SIDE ->
+ SideBySideLayout(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ isUserSwitcherVisible = isFullScreenUserSwitcherEnabled,
+ modifier = modifier,
+ )
+ BouncerSceneLayout.STACKED ->
+ StackedLayout(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ isUserSwitcherVisible = isFullScreenUserSwitcherEnabled,
+ modifier = modifier,
+ )
+ BouncerSceneLayout.SPLIT ->
+ SplitLayout(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ modifier = modifier,
+ )
+ }
+}
+
+/**
+ * Renders the contents of the actual bouncer UI, the area that takes user input to do an
+ * authentication attempt, including all messaging UI (directives, reasoning, errors, etc.).
+ */
+@Composable
+private fun StandardLayout(
+ viewModel: BouncerViewModel,
+ dialogFactory: BouncerDialogFactory,
+ modifier: Modifier = Modifier,
+ outputOnly: Boolean = false,
+) {
+ val foldPosture: FoldPosture by foldPosture()
+ val isSplitAroundTheFoldRequired by viewModel.isFoldSplitRequired.collectAsState()
+ val isSplitAroundTheFold =
+ foldPosture == FoldPosture.Tabletop && !outputOnly && isSplitAroundTheFoldRequired
+ val currentSceneKey =
+ if (isSplitAroundTheFold) SceneKeys.SplitSceneKey else SceneKeys.ContiguousSceneKey
+
+ SceneTransitionLayout(
+ currentScene = currentSceneKey,
+ onChangeScene = {},
+ transitions = SceneTransitions,
+ modifier = modifier,
+ ) {
+ scene(SceneKeys.ContiguousSceneKey) {
+ FoldSplittable(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ outputOnly = outputOnly,
+ isSplit = false,
+ )
+ }
+
+ scene(SceneKeys.SplitSceneKey) {
+ FoldSplittable(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ outputOnly = outputOnly,
+ isSplit = true,
+ )
+ }
+ }
+}
+
+/**
+ * Renders the "standard" layout of the bouncer, where the bouncer is rendered on its own (no user
+ * switcher UI) and laid out vertically, centered horizontally.
+ *
+ * If [isSplit] is `true`, the top and bottom parts of the bouncer are split such that they don't
+ * render across the location of the fold hardware when the device is fully or part-way unfolded
+ * with the fold hinge in a horizontal position.
+ *
+ * If [outputOnly] is `true`, only the "output" part of the UI is shown (where the entered PIN
+ * "shapes" appear), if `false`, the entire UI is shown, including the area where the user can enter
+ * their PIN or pattern.
+ */
+@Composable
+private fun SceneScope.FoldSplittable(
+ viewModel: BouncerViewModel,
+ dialogFactory: BouncerDialogFactory,
+ outputOnly: Boolean,
+ isSplit: Boolean,
+ modifier: Modifier = Modifier,
+) {
+ val message: BouncerViewModel.MessageViewModel by viewModel.message.collectAsState()
+ val dialogMessage: String? by viewModel.throttlingDialogMessage.collectAsState()
+ var dialog: Dialog? by remember { mutableStateOf(null) }
+ val actionButton: BouncerActionButtonModel? by viewModel.actionButton.collectAsState()
+ val splitRatio =
+ LocalContext.current.resources.getFloat(
+ R.dimen.motion_layout_half_fold_bouncer_height_ratio
+ )
+
+ Column(modifier = modifier.padding(horizontal = 32.dp)) {
+ // Content above the fold, when split on a foldable device in a "table top" posture:
+ Box(
+ modifier =
+ Modifier.element(SceneElements.AboveFold).fillMaxWidth().thenIf(isSplit) {
+ Modifier.weight(splitRatio)
+ },
+ ) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier.fillMaxWidth().padding(top = 92.dp),
+ ) {
+ Crossfade(
+ targetState = message,
+ label = "Bouncer message",
+ animationSpec = if (message.isUpdateAnimated) tween() else snap(),
+ ) { message ->
+ Text(
+ text = message.text,
+ color = MaterialTheme.colorScheme.onSurface,
+ style = MaterialTheme.typography.bodyLarge,
+ )
+ }
+
+ Spacer(Modifier.heightIn(min = 21.dp, max = 48.dp))
+
+ UserInputArea(
+ viewModel = viewModel,
+ visibility = UserInputAreaVisibility.OUTPUT_ONLY,
+ )
+ }
+ }
+
+ // Content below the fold, when split on a foldable device in a "table top" posture:
+ Box(
+ modifier =
+ Modifier.element(SceneElements.BelowFold).fillMaxWidth().thenIf(isSplit) {
+ Modifier.weight(1 - splitRatio)
+ },
+ ) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier.fillMaxWidth(),
+ ) {
+ if (!outputOnly) {
+ Box(Modifier.weight(1f)) {
+ UserInputArea(
+ viewModel = viewModel,
+ visibility = UserInputAreaVisibility.INPUT_ONLY,
+ modifier = Modifier.align(Alignment.Center),
+ )
+ }
+ }
+
+ Spacer(Modifier.heightIn(min = 21.dp, max = 48.dp))
+
+ val actionButtonModifier = Modifier.height(56.dp)
+
+ actionButton.let { actionButtonViewModel ->
+ if (actionButtonViewModel != null) {
+ BouncerActionButton(
+ viewModel = actionButtonViewModel,
+ modifier = actionButtonModifier,
+ )
+ } else {
+ Spacer(modifier = actionButtonModifier)
+ }
+ }
+
+ Spacer(Modifier.height(48.dp))
+ }
+ }
+
+ if (dialogMessage != null) {
+ if (dialog == null) {
+ dialog =
+ dialogFactory().apply {
+ setMessage(dialogMessage)
+ setButton(
+ DialogInterface.BUTTON_NEUTRAL,
+ context.getString(R.string.ok),
+ ) { _, _ ->
+ viewModel.onThrottlingDialogDismissed()
+ }
+ setCancelable(false)
+ setCanceledOnTouchOutside(false)
+ show()
+ }
+ }
+ } else {
+ dialog?.dismiss()
+ dialog = null
+ }
+ }
+}
+
+/**
+ * Renders the user input area, where the user interacts with the UI to enter their credentials.
+ *
+ * For example, this can be the pattern input area, the password text box, or pin pad.
+ */
+@Composable
+private fun UserInputArea(
+ viewModel: BouncerViewModel,
+ visibility: UserInputAreaVisibility,
+ modifier: Modifier = Modifier,
+) {
+ val authMethodViewModel: AuthMethodBouncerViewModel? by
+ viewModel.authMethodViewModel.collectAsState()
+
+ when (val nonNullViewModel = authMethodViewModel) {
+ is PinBouncerViewModel ->
+ when (visibility) {
+ UserInputAreaVisibility.OUTPUT_ONLY ->
+ PinInputDisplay(
+ viewModel = nonNullViewModel,
+ modifier = modifier,
+ )
+ UserInputAreaVisibility.INPUT_ONLY ->
+ PinPad(
+ viewModel = nonNullViewModel,
+ modifier = modifier,
+ )
+ }
+ is PasswordBouncerViewModel ->
+ if (visibility == UserInputAreaVisibility.INPUT_ONLY) {
+ PasswordBouncer(
+ viewModel = nonNullViewModel,
+ modifier = modifier,
+ )
+ }
+ is PatternBouncerViewModel ->
+ if (visibility == UserInputAreaVisibility.INPUT_ONLY) {
+ PatternBouncer(
+ viewModel = nonNullViewModel,
+ modifier = modifier.aspectRatio(1f, matchHeightConstraintsFirst = false)
+ )
+ }
+ else -> Unit
+ }
+}
+
+/**
+ * Renders the action button on the bouncer, which triggers either Return to Call or Emergency Call.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+private fun BouncerActionButton(
+ viewModel: BouncerActionButtonModel,
+ modifier: Modifier = Modifier,
+) {
+ Button(
+ onClick = viewModel.onClick,
+ modifier =
+ modifier.thenIf(viewModel.onLongClick != null) {
+ Modifier.combinedClickable(
+ onClick = viewModel.onClick,
+ onLongClick = viewModel.onLongClick,
+ )
+ },
+ colors =
+ ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.colorScheme.tertiaryContainer,
+ contentColor = MaterialTheme.colorScheme.onTertiaryContainer,
+ ),
+ ) {
+ Text(
+ text = viewModel.label,
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ }
+}
+
+/** Renders the UI of the user switcher that's displayed on large screens next to the bouncer UI. */
+@Composable
+private fun UserSwitcher(
+ viewModel: BouncerViewModel,
+ modifier: Modifier = Modifier,
+) {
+ val selectedUserImage by viewModel.selectedUserImage.collectAsState(null)
+ val dropdownItems by viewModel.userSwitcherDropdown.collectAsState(emptyList())
+
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center,
+ modifier = modifier,
+ ) {
+ selectedUserImage?.let {
+ Image(
+ bitmap = it.asImageBitmap(),
+ contentDescription = null,
+ modifier = Modifier.size(SelectedUserImageSize),
+ )
+ }
+
+ val (isDropdownExpanded, setDropdownExpanded) = remember { mutableStateOf(false) }
+
+ dropdownItems.firstOrNull()?.let { firstDropdownItem ->
+ Spacer(modifier = Modifier.height(40.dp))
+
+ Box {
+ PlatformButton(
+ modifier =
+ Modifier
+ // Remove the built-in padding applied inside PlatformButton:
+ .padding(vertical = 0.dp)
+ .width(UserSwitcherDropdownWidth)
+ .height(UserSwitcherDropdownHeight),
+ colors =
+ ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
+ contentColor = MaterialTheme.colorScheme.onSurface,
+ ),
+ onClick = { setDropdownExpanded(!isDropdownExpanded) },
+ ) {
+ val context = LocalContext.current
+ Text(
+ text = checkNotNull(firstDropdownItem.text.loadText(context)),
+ style = MaterialTheme.typography.headlineSmall,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ )
+
+ Spacer(modifier = Modifier.weight(1f))
+
+ Icon(
+ imageVector = Icons.Default.KeyboardArrowDown,
+ contentDescription = null,
+ modifier = Modifier.size(32.dp),
+ )
+ }
+
+ UserSwitcherDropdownMenu(
+ isExpanded = isDropdownExpanded,
+ items = dropdownItems,
+ onDismissed = { setDropdownExpanded(false) },
+ )
+ }
+ }
+ }
+}
+
+/**
+ * Renders the dropdown menu that displays the actual users and/or user actions that can be
+ * selected.
+ */
+@Composable
+private fun UserSwitcherDropdownMenu(
+ isExpanded: Boolean,
+ items: List<BouncerViewModel.UserSwitcherDropdownItemViewModel>,
+ onDismissed: () -> Unit,
+) {
+ val context = LocalContext.current
+
+ // TODO(b/303071855): once the FR is fixed, remove this composition local override.
+ MaterialTheme(
+ colorScheme =
+ MaterialTheme.colorScheme.copy(
+ surface = MaterialTheme.colorScheme.surfaceContainerHighest,
+ ),
+ shapes = MaterialTheme.shapes.copy(extraSmall = RoundedCornerShape(28.dp)),
+ ) {
+ DropdownMenu(
+ expanded = isExpanded,
+ onDismissRequest = onDismissed,
+ offset =
+ DpOffset(
+ x = 0.dp,
+ y = -UserSwitcherDropdownHeight,
+ ),
+ modifier = Modifier.width(UserSwitcherDropdownWidth),
+ ) {
+ items.forEach { userSwitcherDropdownItem ->
+ DropdownMenuItem(
+ leadingIcon = {
+ Icon(
+ icon = userSwitcherDropdownItem.icon,
+ tint = MaterialTheme.colorScheme.primary,
+ modifier = Modifier.size(28.dp),
+ )
+ },
+ text = {
+ Text(
+ text = checkNotNull(userSwitcherDropdownItem.text.loadText(context)),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onSurface,
+ )
+ },
+ onClick = {
+ onDismissed()
+ userSwitcherDropdownItem.onClick()
+ },
+ )
+ }
+ }
+ }
+}
+
+/**
+ * Renders the bouncer UI in split mode, with half on one side and half on the other side, swappable
+ * by double-tapping on the side.
+ */
+@Composable
+private fun SplitLayout(
+ viewModel: BouncerViewModel,
+ dialogFactory: BouncerDialogFactory,
+ modifier: Modifier = Modifier,
+) {
+ SwappableLayout(
+ startContent = { startContentModifier ->
+ StandardLayout(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ outputOnly = true,
+ modifier = startContentModifier,
+ )
+ },
+ endContent = { endContentModifier ->
+ UserInputArea(
+ viewModel = viewModel,
+ visibility = UserInputAreaVisibility.INPUT_ONLY,
+ modifier = endContentModifier,
+ )
+ },
+ modifier = modifier
+ )
+}
+
+/**
+ * Arranges the given two contents side-by-side, supporting a double tap anywhere on the background
+ * to flip their positions.
+ */
+@Composable
+private fun SwappableLayout(
+ startContent: @Composable (Modifier) -> Unit,
+ endContent: @Composable (Modifier) -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ val layoutDirection = LocalLayoutDirection.current
+ val isLeftToRight = layoutDirection == LayoutDirection.Ltr
+ val (isSwapped, setSwapped) = rememberSaveable(isLeftToRight) { mutableStateOf(!isLeftToRight) }
+
+ Row(
+ modifier =
+ modifier.pointerInput(Unit) {
+ detectTapGestures(
+ onDoubleTap = { offset ->
+ // Depending on where the user double tapped, switch the elements such that
+ // the endContent is closer to the side that was double tapped.
+ setSwapped(offset.x < size.width / 2)
+ }
+ )
+ },
+ ) {
+ val animatedOffset by
+ animateFloatAsState(
+ targetValue =
+ if (!isSwapped) {
+ // When startContent is first, both elements have their natural placement so
+ // they are not offset in any way.
+ 0f
+ } else if (isLeftToRight) {
+ // Since startContent is not first, the elements have to be swapped
+ // horizontally. In the case of LTR locales, this means pushing startContent
+ // to the right, hence the positive number.
+ 1f
+ } else {
+ // Since startContent is not first, the elements have to be swapped
+ // horizontally. In the case of RTL locales, this means pushing startContent
+ // to the left, hence the negative number.
+ -1f
+ },
+ label = "offset",
+ )
+
+ startContent(
+ Modifier.fillMaxHeight().weight(1f).graphicsLayer {
+ translationX = size.width * animatedOffset
+ alpha = animatedAlpha(animatedOffset)
+ }
+ )
+
+ Box(
+ modifier =
+ Modifier.fillMaxHeight().weight(1f).graphicsLayer {
+ // A negative sign is used to make sure this is offset in the direction that's
+ // opposite of the direction that the user switcher is pushed in.
+ translationX = -size.width * animatedOffset
+ alpha = animatedAlpha(animatedOffset)
+ }
+ ) {
+ endContent(Modifier.widthIn(max = 400.dp).align(Alignment.BottomCenter))
+ }
+ }
+}
+
+/**
+ * Arranges the bouncer contents and user switcher contents side-by-side, supporting a double tap
+ * anywhere on the background to flip their positions.
+ *
+ * In situations when [isUserSwitcherVisible] is `false`, one of two things may happen: either the
+ * UI for the bouncer will be shown on its own, taking up one side, with the other side just being
+ * empty space or, if that kind of "stand-alone side-by-side" isn't supported, the standard
+ * rendering of the bouncer will be used instead of the side-by-side layout.
+ */
+@Composable
+private fun SideBySideLayout(
+ viewModel: BouncerViewModel,
+ dialogFactory: BouncerDialogFactory,
+ isUserSwitcherVisible: Boolean,
+ modifier: Modifier = Modifier,
+) {
+ SwappableLayout(
+ startContent = { startContentModifier ->
+ if (isUserSwitcherVisible) {
+ UserSwitcher(
+ viewModel = viewModel,
+ modifier = startContentModifier,
+ )
+ } else {
+ Box(
+ modifier = startContentModifier,
+ )
+ }
+ },
+ endContent = { endContentModifier ->
+ StandardLayout(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ modifier = endContentModifier,
+ )
+ },
+ modifier = modifier,
+ )
+}
+
+/** Arranges the bouncer contents and user switcher contents one on top of the other, vertically. */
+@Composable
+private fun StackedLayout(
+ viewModel: BouncerViewModel,
+ dialogFactory: BouncerDialogFactory,
+ isUserSwitcherVisible: Boolean,
+ modifier: Modifier = Modifier,
+) {
+ Column(
+ modifier = modifier,
+ ) {
+ if (isUserSwitcherVisible) {
+ UserSwitcher(
+ viewModel = viewModel,
+ modifier = Modifier.fillMaxWidth().weight(1f),
+ )
+ }
+
+ StandardLayout(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ modifier = Modifier.fillMaxWidth().weight(1f),
+ )
+ }
+}
+
+interface BouncerDialogFactory {
+ operator fun invoke(): AlertDialog
+}
+
+/** Enumerates all supported user-input area visibilities. */
+private enum class UserInputAreaVisibility {
+ /**
+ * Only the area where the user enters the input is shown; the area where the input is reflected
+ * back to the user is not shown.
+ */
+ INPUT_ONLY,
+ /**
+ * Only the area where the input is reflected back to the user is shown; the area where the
+ * input is entered by the user is not shown.
+ */
+ OUTPUT_ONLY,
+}
+
+/**
+ * Calculates an alpha for the user switcher and bouncer such that it's at `1` when the offset of
+ * the two reaches a stopping point but `0` in the middle of the transition.
+ */
+private fun animatedAlpha(
+ offset: Float,
+): Float {
+ // Describes a curve that is made of two parabolic U-shaped curves mirrored horizontally around
+ // the y-axis. The U on the left runs between x = -1 and x = 0 while the U on the right runs
+ // between x = 0 and x = 1.
+ //
+ // The minimum values of the curves are at -0.5 and +0.5.
+ //
+ // Both U curves are vertically scaled such that they reach the points (-1, 1) and (1, 1).
+ //
+ // Breaking it down, it's y = a×(|x|-m)²+b, where:
+ // x: the offset
+ // y: the alpha
+ // m: x-axis center of the parabolic curves, where the minima are.
+ // b: y-axis offset to apply to the entire curve so the animation spends more time with alpha =
+ // 0.
+ // a: amplitude to scale the parabolic curves to reach y = 1 at x = -1, x = 0, and x = +1.
+ val m = 0.5f
+ val b = -0.25
+ val a = (1 - b) / m.pow(2)
+
+ return max(0f, (a * (abs(offset) - m).pow(2) + b).toFloat())
+}
+
+private val SelectedUserImageSize = 190.dp
+private val UserSwitcherDropdownWidth = SelectedUserImageSize + 2 * 29.dp
+private val UserSwitcherDropdownHeight = 60.dp
+
+private object SceneKeys {
+ val ContiguousSceneKey = SceneKey("default")
+ val SplitSceneKey = SceneKey("split")
+}
+
+private object SceneElements {
+ val AboveFold = ElementKey("above_fold")
+ val BelowFold = ElementKey("below_fold")
+}
+
+private val SceneTransitions = transitions {
+ from(SceneKeys.ContiguousSceneKey, to = SceneKeys.SplitSceneKey) { spec = tween() }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 57af2ba59566..d638ffe11abe 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -16,91 +16,22 @@
package com.android.systemui.bouncer.ui.composable
-import android.app.AlertDialog
-import android.app.Dialog
-import android.content.DialogInterface
-import androidx.compose.animation.Crossfade
-import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.core.snap
-import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.combinedClickable
-import androidx.compose.foundation.gestures.detectTapGestures
-import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.aspectRatio
-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.heightIn
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.layout.widthIn
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.KeyboardArrowDown
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.DropdownMenu
-import androidx.compose.material3.DropdownMenuItem
-import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
-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.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.asImageBitmap
-import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.input.pointer.pointerInput
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalLayoutDirection
-import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.DpOffset
-import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.times
-import com.android.compose.PlatformButton
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.SceneKey as SceneTransitionLayoutSceneKey
import com.android.compose.animation.scene.SceneScope
-import com.android.compose.animation.scene.SceneTransitionLayout
-import com.android.compose.animation.scene.transitions
-import com.android.compose.modifiers.thenIf
-import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel
-import com.android.systemui.bouncer.ui.helper.BouncerSceneLayout
-import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
-import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
-import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
-import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
-import com.android.systemui.common.shared.model.Text.Companion.loadText
-import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.fold.ui.composable.foldPosture
-import com.android.systemui.fold.ui.helper.FoldPosture
-import com.android.systemui.res.R
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.ui.composable.ComposableScene
import javax.inject.Inject
-import kotlin.math.abs
-import kotlin.math.max
-import kotlin.math.pow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -118,7 +49,7 @@ class BouncerScene
@Inject
constructor(
private val viewModel: BouncerViewModel,
- private val dialogFactory: BouncerSceneDialogFactory,
+ private val dialogFactory: BouncerDialogFactory,
) : ComposableScene {
override val key = SceneKey.Bouncer
@@ -140,648 +71,22 @@ constructor(
@Composable
private fun SceneScope.BouncerScene(
viewModel: BouncerViewModel,
- dialogFactory: BouncerSceneDialogFactory,
+ dialogFactory: BouncerDialogFactory,
modifier: Modifier = Modifier,
) {
val backgroundColor = MaterialTheme.colorScheme.surface
- val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsState()
- val layout = calculateLayout(isSideBySideSupported = isSideBySideSupported)
Box(modifier) {
Canvas(Modifier.element(Bouncer.Elements.Background).fillMaxSize()) {
drawRect(color = backgroundColor)
}
- val childModifier = Modifier.element(Bouncer.Elements.Content).fillMaxSize()
- val isFullScreenUserSwitcherEnabled = viewModel.isUserSwitcherVisible
-
- when (layout) {
- BouncerSceneLayout.STANDARD ->
- StandardLayout(
- viewModel = viewModel,
- dialogFactory = dialogFactory,
- modifier = childModifier,
- )
- BouncerSceneLayout.SIDE_BY_SIDE ->
- SideBySideLayout(
- viewModel = viewModel,
- dialogFactory = dialogFactory,
- isUserSwitcherVisible = isFullScreenUserSwitcherEnabled,
- modifier = childModifier,
- )
- BouncerSceneLayout.STACKED ->
- StackedLayout(
- viewModel = viewModel,
- dialogFactory = dialogFactory,
- isUserSwitcherVisible = isFullScreenUserSwitcherEnabled,
- modifier = childModifier,
- )
- BouncerSceneLayout.SPLIT ->
- SplitLayout(
- viewModel = viewModel,
- dialogFactory = dialogFactory,
- modifier = childModifier,
- )
- }
- }
-}
-
-/**
- * Renders the contents of the actual bouncer UI, the area that takes user input to do an
- * authentication attempt, including all messaging UI (directives, reasoning, errors, etc.).
- */
-@Composable
-private fun StandardLayout(
- viewModel: BouncerViewModel,
- dialogFactory: BouncerSceneDialogFactory,
- modifier: Modifier = Modifier,
- outputOnly: Boolean = false,
-) {
- val foldPosture: FoldPosture by foldPosture()
- val isSplitAroundTheFoldRequired by viewModel.isFoldSplitRequired.collectAsState()
- val isSplitAroundTheFold =
- foldPosture == FoldPosture.Tabletop && !outputOnly && isSplitAroundTheFoldRequired
- val currentSceneKey =
- if (isSplitAroundTheFold) SceneKeys.SplitSceneKey else SceneKeys.ContiguousSceneKey
-
- SceneTransitionLayout(
- currentScene = currentSceneKey,
- onChangeScene = {},
- transitions = SceneTransitions,
- modifier = modifier,
- ) {
- scene(SceneKeys.ContiguousSceneKey) {
- FoldSplittable(
- viewModel = viewModel,
- dialogFactory = dialogFactory,
- outputOnly = outputOnly,
- isSplit = false,
- )
- }
-
- scene(SceneKeys.SplitSceneKey) {
- FoldSplittable(
- viewModel = viewModel,
- dialogFactory = dialogFactory,
- outputOnly = outputOnly,
- isSplit = true,
- )
- }
- }
-}
-
-/**
- * Renders the "standard" layout of the bouncer, where the bouncer is rendered on its own (no user
- * switcher UI) and laid out vertically, centered horizontally.
- *
- * If [isSplit] is `true`, the top and bottom parts of the bouncer are split such that they don't
- * render across the location of the fold hardware when the device is fully or part-way unfolded
- * with the fold hinge in a horizontal position.
- *
- * If [outputOnly] is `true`, only the "output" part of the UI is shown (where the entered PIN
- * "shapes" appear), if `false`, the entire UI is shown, including the area where the user can enter
- * their PIN or pattern.
- */
-@Composable
-private fun SceneScope.FoldSplittable(
- viewModel: BouncerViewModel,
- dialogFactory: BouncerSceneDialogFactory,
- outputOnly: Boolean,
- isSplit: Boolean,
- modifier: Modifier = Modifier,
-) {
- val message: BouncerViewModel.MessageViewModel by viewModel.message.collectAsState()
- val dialogMessage: String? by viewModel.throttlingDialogMessage.collectAsState()
- var dialog: Dialog? by remember { mutableStateOf(null) }
- val actionButton: BouncerActionButtonModel? by viewModel.actionButton.collectAsState()
- val splitRatio =
- LocalContext.current.resources.getFloat(
- R.dimen.motion_layout_half_fold_bouncer_height_ratio
- )
-
- Column(modifier = modifier.padding(horizontal = 32.dp)) {
- // Content above the fold, when split on a foldable device in a "table top" posture:
- Box(
- modifier =
- Modifier.element(SceneElements.AboveFold).fillMaxWidth().thenIf(isSplit) {
- Modifier.weight(splitRatio)
- },
- ) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.fillMaxWidth().padding(top = 92.dp),
- ) {
- Crossfade(
- targetState = message,
- label = "Bouncer message",
- animationSpec = if (message.isUpdateAnimated) tween() else snap(),
- ) { message ->
- Text(
- text = message.text,
- color = MaterialTheme.colorScheme.onSurface,
- style = MaterialTheme.typography.bodyLarge,
- )
- }
-
- Spacer(Modifier.heightIn(min = 21.dp, max = 48.dp))
-
- UserInputArea(
- viewModel = viewModel,
- visibility = UserInputAreaVisibility.OUTPUT_ONLY,
- )
- }
- }
-
- // Content below the fold, when split on a foldable device in a "table top" posture:
- Box(
- modifier =
- Modifier.element(SceneElements.BelowFold).fillMaxWidth().thenIf(isSplit) {
- Modifier.weight(1 - splitRatio)
- },
- ) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.fillMaxWidth(),
- ) {
- if (!outputOnly) {
- Box(Modifier.weight(1f)) {
- UserInputArea(
- viewModel = viewModel,
- visibility = UserInputAreaVisibility.INPUT_ONLY,
- modifier = Modifier.align(Alignment.Center),
- )
- }
- }
-
- Spacer(Modifier.heightIn(min = 21.dp, max = 48.dp))
-
- val actionButtonModifier = Modifier.height(56.dp)
-
- actionButton.let { actionButtonViewModel ->
- if (actionButtonViewModel != null) {
- BouncerActionButton(
- viewModel = actionButtonViewModel,
- modifier = actionButtonModifier,
- )
- } else {
- Spacer(modifier = actionButtonModifier)
- }
- }
-
- Spacer(Modifier.height(48.dp))
- }
- }
-
- if (dialogMessage != null) {
- if (dialog == null) {
- dialog =
- dialogFactory().apply {
- setMessage(dialogMessage)
- setButton(
- DialogInterface.BUTTON_NEUTRAL,
- context.getString(R.string.ok),
- ) { _, _ ->
- viewModel.onThrottlingDialogDismissed()
- }
- setCancelable(false)
- setCanceledOnTouchOutside(false)
- show()
- }
- }
- } else {
- dialog?.dismiss()
- dialog = null
- }
- }
-}
-
-/**
- * Renders the user input area, where the user interacts with the UI to enter their credentials.
- *
- * For example, this can be the pattern input area, the password text box, or pin pad.
- */
-@Composable
-private fun UserInputArea(
- viewModel: BouncerViewModel,
- visibility: UserInputAreaVisibility,
- modifier: Modifier = Modifier,
-) {
- val authMethodViewModel: AuthMethodBouncerViewModel? by
- viewModel.authMethodViewModel.collectAsState()
-
- when (val nonNullViewModel = authMethodViewModel) {
- is PinBouncerViewModel ->
- when (visibility) {
- UserInputAreaVisibility.OUTPUT_ONLY ->
- PinInputDisplay(
- viewModel = nonNullViewModel,
- modifier = modifier,
- )
- UserInputAreaVisibility.INPUT_ONLY ->
- PinPad(
- viewModel = nonNullViewModel,
- modifier = modifier,
- )
- }
- is PasswordBouncerViewModel ->
- if (visibility == UserInputAreaVisibility.INPUT_ONLY) {
- PasswordBouncer(
- viewModel = nonNullViewModel,
- modifier = modifier,
- )
- }
- is PatternBouncerViewModel ->
- if (visibility == UserInputAreaVisibility.INPUT_ONLY) {
- PatternBouncer(
- viewModel = nonNullViewModel,
- modifier = modifier.aspectRatio(1f, matchHeightConstraintsFirst = false)
- )
- }
- else -> Unit
- }
-}
-
-/**
- * Renders the action button on the bouncer, which triggers either Return to Call or Emergency Call.
- */
-@OptIn(ExperimentalFoundationApi::class)
-@Composable
-private fun BouncerActionButton(
- viewModel: BouncerActionButtonModel,
- modifier: Modifier = Modifier,
-) {
- Button(
- onClick = viewModel.onClick,
- modifier =
- modifier.thenIf(viewModel.onLongClick != null) {
- Modifier.combinedClickable(
- onClick = viewModel.onClick,
- onLongClick = viewModel.onLongClick,
- )
- },
- colors =
- ButtonDefaults.buttonColors(
- containerColor = MaterialTheme.colorScheme.tertiaryContainer,
- contentColor = MaterialTheme.colorScheme.onTertiaryContainer,
- ),
- ) {
- Text(
- text = viewModel.label,
- style = MaterialTheme.typography.bodyMedium,
+ // Separate the bouncer content into a reusable composable that doesn't have any SceneScope
+ // dependencies
+ BouncerContent(
+ viewModel,
+ dialogFactory,
+ Modifier.element(Bouncer.Elements.Content).fillMaxSize()
)
}
}
-
-/** Renders the UI of the user switcher that's displayed on large screens next to the bouncer UI. */
-@Composable
-private fun UserSwitcher(
- viewModel: BouncerViewModel,
- modifier: Modifier = Modifier,
-) {
- val selectedUserImage by viewModel.selectedUserImage.collectAsState(null)
- val dropdownItems by viewModel.userSwitcherDropdown.collectAsState(emptyList())
-
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.Center,
- modifier = modifier,
- ) {
- selectedUserImage?.let {
- Image(
- bitmap = it.asImageBitmap(),
- contentDescription = null,
- modifier = Modifier.size(SelectedUserImageSize),
- )
- }
-
- val (isDropdownExpanded, setDropdownExpanded) = remember { mutableStateOf(false) }
-
- dropdownItems.firstOrNull()?.let { firstDropdownItem ->
- Spacer(modifier = Modifier.height(40.dp))
-
- Box {
- PlatformButton(
- modifier =
- Modifier
- // Remove the built-in padding applied inside PlatformButton:
- .padding(vertical = 0.dp)
- .width(UserSwitcherDropdownWidth)
- .height(UserSwitcherDropdownHeight),
- colors =
- ButtonDefaults.buttonColors(
- containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
- contentColor = MaterialTheme.colorScheme.onSurface,
- ),
- onClick = { setDropdownExpanded(!isDropdownExpanded) },
- ) {
- val context = LocalContext.current
- Text(
- text = checkNotNull(firstDropdownItem.text.loadText(context)),
- style = MaterialTheme.typography.headlineSmall,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- )
-
- Spacer(modifier = Modifier.weight(1f))
-
- Icon(
- imageVector = Icons.Default.KeyboardArrowDown,
- contentDescription = null,
- modifier = Modifier.size(32.dp),
- )
- }
-
- UserSwitcherDropdownMenu(
- isExpanded = isDropdownExpanded,
- items = dropdownItems,
- onDismissed = { setDropdownExpanded(false) },
- )
- }
- }
- }
-}
-
-/**
- * Renders the dropdowm menu that displays the actual users and/or user actions that can be
- * selected.
- */
-@Composable
-private fun UserSwitcherDropdownMenu(
- isExpanded: Boolean,
- items: List<BouncerViewModel.UserSwitcherDropdownItemViewModel>,
- onDismissed: () -> Unit,
-) {
- val context = LocalContext.current
-
- // TODO(b/303071855): once the FR is fixed, remove this composition local override.
- MaterialTheme(
- colorScheme =
- MaterialTheme.colorScheme.copy(
- surface = MaterialTheme.colorScheme.surfaceContainerHighest,
- ),
- shapes = MaterialTheme.shapes.copy(extraSmall = RoundedCornerShape(28.dp)),
- ) {
- DropdownMenu(
- expanded = isExpanded,
- onDismissRequest = onDismissed,
- offset =
- DpOffset(
- x = 0.dp,
- y = -UserSwitcherDropdownHeight,
- ),
- modifier = Modifier.width(UserSwitcherDropdownWidth),
- ) {
- items.forEach { userSwitcherDropdownItem ->
- DropdownMenuItem(
- leadingIcon = {
- Icon(
- icon = userSwitcherDropdownItem.icon,
- tint = MaterialTheme.colorScheme.primary,
- modifier = Modifier.size(28.dp),
- )
- },
- text = {
- Text(
- text = checkNotNull(userSwitcherDropdownItem.text.loadText(context)),
- style = MaterialTheme.typography.bodyLarge,
- color = MaterialTheme.colorScheme.onSurface,
- )
- },
- onClick = {
- onDismissed()
- userSwitcherDropdownItem.onClick()
- },
- )
- }
- }
- }
-}
-
-/**
- * Renders the bouncer UI in split mode, with half on one side and half on the other side, swappable
- * by double-tapping on the side.
- */
-@Composable
-private fun SplitLayout(
- viewModel: BouncerViewModel,
- dialogFactory: BouncerSceneDialogFactory,
- modifier: Modifier = Modifier,
-) {
- SwappableLayout(
- startContent = { startContentModifier ->
- StandardLayout(
- viewModel = viewModel,
- dialogFactory = dialogFactory,
- outputOnly = true,
- modifier = startContentModifier,
- )
- },
- endContent = { endContentModifier ->
- UserInputArea(
- viewModel = viewModel,
- visibility = UserInputAreaVisibility.INPUT_ONLY,
- modifier = endContentModifier,
- )
- },
- modifier = modifier
- )
-}
-
-/**
- * Arranges the given two contents side-by-side, supporting a double tap anywhere on the background
- * to flip their positions.
- */
-@Composable
-private fun SwappableLayout(
- startContent: @Composable (Modifier) -> Unit,
- endContent: @Composable (Modifier) -> Unit,
- modifier: Modifier = Modifier,
-) {
- val layoutDirection = LocalLayoutDirection.current
- val isLeftToRight = layoutDirection == LayoutDirection.Ltr
- val (isSwapped, setSwapped) = rememberSaveable(isLeftToRight) { mutableStateOf(!isLeftToRight) }
-
- Row(
- modifier =
- modifier.pointerInput(Unit) {
- detectTapGestures(
- onDoubleTap = { offset ->
- // Depending on where the user double tapped, switch the elements such that
- // the endContent is closer to the side that was double tapped.
- setSwapped(offset.x < size.width / 2)
- }
- )
- },
- ) {
- val animatedOffset by
- animateFloatAsState(
- targetValue =
- if (!isSwapped) {
- // When startContent is first, both elements have their natural placement so
- // they are not offset in any way.
- 0f
- } else if (isLeftToRight) {
- // Since startContent is not first, the elements have to be swapped
- // horizontally. In the case of LTR locales, this means pushing startContent
- // to the right, hence the positive number.
- 1f
- } else {
- // Since startContent is not first, the elements have to be swapped
- // horizontally. In the case of RTL locales, this means pushing startContent
- // to the left, hence the negative number.
- -1f
- },
- label = "offset",
- )
-
- startContent(
- Modifier.fillMaxHeight().weight(1f).graphicsLayer {
- translationX = size.width * animatedOffset
- alpha = animatedAlpha(animatedOffset)
- }
- )
-
- Box(
- modifier =
- Modifier.fillMaxHeight().weight(1f).graphicsLayer {
- // A negative sign is used to make sure this is offset in the direction that's
- // opposite of the direction that the user switcher is pushed in.
- translationX = -size.width * animatedOffset
- alpha = animatedAlpha(animatedOffset)
- }
- ) {
- endContent(Modifier.widthIn(max = 400.dp).align(Alignment.BottomCenter))
- }
- }
-}
-
-/**
- * Arranges the bouncer contents and user switcher contents side-by-side, supporting a double tap
- * anywhere on the background to flip their positions.
- *
- * In situations when [isUserSwitcherVisible] is `false`, one of two things may happen: either the
- * UI for the bouncer will be shown on its own, taking up one side, with the other side just being
- * empty space or, if that kind of "stand-alone side-by-side" isn't supported, the standard
- * rendering of the bouncer will be used instead of the side-by-side layout.
- */
-@Composable
-private fun SideBySideLayout(
- viewModel: BouncerViewModel,
- dialogFactory: BouncerSceneDialogFactory,
- isUserSwitcherVisible: Boolean,
- modifier: Modifier = Modifier,
-) {
- SwappableLayout(
- startContent = { startContentModifier ->
- if (isUserSwitcherVisible) {
- UserSwitcher(
- viewModel = viewModel,
- modifier = startContentModifier,
- )
- } else {
- Box(
- modifier = startContentModifier,
- )
- }
- },
- endContent = { endContentModifier ->
- StandardLayout(
- viewModel = viewModel,
- dialogFactory = dialogFactory,
- modifier = endContentModifier,
- )
- },
- modifier = modifier,
- )
-}
-
-/** Arranges the bouncer contents and user switcher contents one on top of the other, vertically. */
-@Composable
-private fun StackedLayout(
- viewModel: BouncerViewModel,
- dialogFactory: BouncerSceneDialogFactory,
- isUserSwitcherVisible: Boolean,
- modifier: Modifier = Modifier,
-) {
- Column(
- modifier = modifier,
- ) {
- if (isUserSwitcherVisible) {
- UserSwitcher(
- viewModel = viewModel,
- modifier = Modifier.fillMaxWidth().weight(1f),
- )
- }
-
- StandardLayout(
- viewModel = viewModel,
- dialogFactory = dialogFactory,
- modifier = Modifier.fillMaxWidth().weight(1f),
- )
- }
-}
-
-interface BouncerSceneDialogFactory {
- operator fun invoke(): AlertDialog
-}
-
-/** Enumerates all supported user-input area visibilities. */
-private enum class UserInputAreaVisibility {
- /**
- * Only the area where the user enters the input is shown; the area where the input is reflected
- * back to the user is not shown.
- */
- INPUT_ONLY,
- /**
- * Only the area where the input is reflected back to the user is shown; the area where the
- * input is entered by the user is not shown.
- */
- OUTPUT_ONLY,
-}
-
-/**
- * Calculates an alpha for the user switcher and bouncer such that it's at `1` when the offset of
- * the two reaches a stopping point but `0` in the middle of the transition.
- */
-private fun animatedAlpha(
- offset: Float,
-): Float {
- // Describes a curve that is made of two parabolic U-shaped curves mirrored horizontally around
- // the y-axis. The U on the left runs between x = -1 and x = 0 while the U on the right runs
- // between x = 0 and x = 1.
- //
- // The minimum values of the curves are at -0.5 and +0.5.
- //
- // Both U curves are vertically scaled such that they reach the points (-1, 1) and (1, 1).
- //
- // Breaking it down, it's y = a×(|x|-m)²+b, where:
- // x: the offset
- // y: the alpha
- // m: x-axis center of the parabolic curves, where the minima are.
- // b: y-axis offset to apply to the entire curve so the animation spends more time with alpha =
- // 0.
- // a: amplitude to scale the parabolic curves to reach y = 1 at x = -1, x = 0, and x = +1.
- val m = 0.5f
- val b = -0.25
- val a = (1 - b) / m.pow(2)
-
- return max(0f, (a * (abs(offset) - m).pow(2) + b).toFloat())
-}
-
-private val SelectedUserImageSize = 190.dp
-private val UserSwitcherDropdownWidth = SelectedUserImageSize + 2 * 29.dp
-private val UserSwitcherDropdownHeight = 60.dp
-
-private object SceneKeys {
- val ContiguousSceneKey = SceneTransitionLayoutSceneKey("default")
- val SplitSceneKey = SceneTransitionLayoutSceneKey("split")
-}
-
-private object SceneElements {
- val AboveFold = ElementKey("above_fold")
- val BelowFold = ElementKey("below_fold")
-}
-
-private val SceneTransitions = transitions {
- from(SceneKeys.ContiguousSceneKey, to = SceneKeys.SplitSceneKey) { spec = tween() }
-}
diff --git a/packages/SystemUI/res/anim/instant_fade_out.xml b/packages/SystemUI/res/anim/instant_fade_out.xml
new file mode 100644
index 000000000000..800420b4ff60
--- /dev/null
+++ b/packages/SystemUI/res/anim/instant_fade_out.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:duration="0"/>
+
diff --git a/packages/SystemUI/res/drawable/ksh_key_item_background.xml b/packages/SystemUI/res/drawable/ksh_key_item_background.xml
index 75ff30d25aa7..1db48fad2e3f 100644
--- a/packages/SystemUI/res/drawable/ksh_key_item_background.xml
+++ b/packages/SystemUI/res/drawable/ksh_key_item_background.xml
@@ -17,5 +17,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/ksh_key_item_background" />
- <corners android:radius="2dp" />
+ <corners android:radius="8dp" />
</shape>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
index fcf9638440c7..a0051008ddd6 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
@@ -22,8 +22,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
- android:paddingStart="24dp"
- android:paddingEnd="24dp"
android:paddingBottom="8dp">
<ImageView
android:id="@+id/keyboard_shortcuts_icon"
@@ -57,5 +55,6 @@
android:layout_alignParentEnd="true"
android:textSize="14sp"
android:scrollHorizontally="false"
- android:layout_centerVertical="true"/>
+ android:layout_centerVertical="true"
+ android:padding="0dp" />
</com.android.systemui.statusbar.KeyboardShortcutAppItemLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
index 0759990f1677..4f100f6b94d1 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
@@ -21,7 +21,5 @@
android:textSize="14sp"
android:fontFamily="sans-serif-medium"
android:importantForAccessibility="yes"
- android:paddingStart="24dp"
android:paddingTop="20dp"
- android:paddingEnd="24dp"
android:paddingBottom="10dp"/>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_icon_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_icon_view.xml
index a3901d084930..f96edbf0056e 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_key_icon_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_icon_view.xml
@@ -18,7 +18,12 @@
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="@dimen/ksh_item_padding"
+ android:minWidth="48dp"
+ android:minHeight="32dp"
+ android:paddingLeft="@dimen/ksh_key_view_padding_horizontal"
+ android:paddingRight="@dimen/ksh_key_view_padding_horizontal"
+ android:paddingTop="@dimen/ksh_key_view_padding_vertical"
+ android:paddingBottom="@dimen/ksh_key_view_padding_vertical"
android:layout_marginStart="@dimen/ksh_item_margin_start"
- android:scaleType="fitXY"
+ android:scaleType="matrix"
android:background="@drawable/ksh_key_item_background" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml
deleted file mode 100644
index a037cb284b5a..000000000000
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="@dimen/ksh_item_padding"
- android:layout_marginLeft="0dp"
- android:layout_marginRight="0dp"
- android:scaleType="fitXY"
- android:tint="?android:attr/textColorPrimary"
- style="@style/ShortcutItemBackground" /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml
deleted file mode 100644
index 727f2c15d5e5..000000000000
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="@dimen/ksh_item_padding"
- android:layout_marginLeft="0dp"
- android:layout_marginRight="0dp"
- android:text="+"
- style="@style/ShortcutItemBackground"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="true"
- android:gravity="center"
- android:textSize="@dimen/ksh_item_text_size"
- android:textAllCaps="true"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_separator_view.xml
index 12b4e150ee2d..8772a732e829 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_separator_view.xml
@@ -14,12 +14,15 @@
limitations under the License.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="@dimen/ksh_item_padding"
- android:layout_marginStart="@dimen/ksh_item_margin_start"
- style="@style/ShortcutItemBackground"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="false"
- android:gravity="center"
- android:textSize="@dimen/ksh_item_text_size"/> \ No newline at end of file
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minHeight="32dp"
+ android:padding="@dimen/ksh_item_padding"
+ android:layout_marginLeft="0dp"
+ android:layout_marginRight="0dp"
+ android:text="@string/keyboard_shortcut_join"
+ android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
+ android:singleLine="true"
+ android:gravity="center"
+ android:textSize="@dimen/ksh_item_text_size" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml
deleted file mode 100644
index 00ef94784740..000000000000
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="@dimen/ksh_item_padding"
- android:layout_marginLeft="0dp"
- android:layout_marginRight="0dp"
- android:text="|"
- style="@style/ShortcutItemBackground"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="true"
- android:gravity="center"
- android:textSize="@dimen/ksh_item_text_size"
- android:textAllCaps="true"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
index b06f7fc3c69d..42bbf25d6c26 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
@@ -14,14 +14,18 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="@dimen/ksh_item_padding"
- android:layout_marginStart="@dimen/ksh_item_margin_start"
- android:background="@drawable/ksh_key_item_background"
- android:textColor="@color/ksh_key_item_color"
- android:singleLine="true"
- android:gravity="center"
- android:textSize="@dimen/ksh_item_text_size"
- android:textAllCaps="true"/>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="32dp"
+ android:minHeight="32dp"
+ android:paddingLeft="@dimen/ksh_key_view_padding_horizontal"
+ android:paddingRight="@dimen/ksh_key_view_padding_horizontal"
+ android:paddingTop="@dimen/ksh_key_view_padding_vertical"
+ android:paddingBottom="@dimen/ksh_key_view_padding_vertical"
+ android:layout_marginStart="@dimen/ksh_item_margin_start"
+ android:background="@drawable/ksh_key_item_background"
+ android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
+ android:singleLine="true"
+ android:gravity="center"
+ android:textSize="@dimen/ksh_item_text_size" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
index dbcd2636134f..61f69c04c174 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
@@ -70,17 +70,14 @@
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginStart="49dp"
+ android:layout_marginEnd="0dp"
android:scrollbars="none">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
- <View
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_marginStart="37dp"/>
-
<Button
android:id="@+id/shortcut_system"
android:layout_width="wrap_content"
@@ -116,6 +113,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
+ android:layout_marginStart="49dp"
+ android:layout_marginEnd="49dp"
android:layout_gravity="center_horizontal"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
@@ -126,8 +125,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
- android:layout_marginStart="25dp"
- android:layout_marginEnd="25dp">
+ android:layout_marginStart="49dp"
+ android:layout_marginEnd="49dp"
+ android:overScrollMode="never"
+ android:layout_marginBottom="16dp">
<LinearLayout
android:id="@+id/keyboard_shortcuts_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
index 7aba1cf6e0dc..9e54ab1dc361 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
@@ -22,6 +22,8 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginEnd="24dp"
android:orientation="vertical">
<ScrollView
android:id="@+id/keyboard_shortcuts_scroll_view"
diff --git a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
index 130472d67500..02c8c3a5202e 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
@@ -17,7 +17,8 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="250dp"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
android:orientation="vertical"
android:padding="12dp">
<TextView
diff --git a/packages/SystemUI/res/layout/screen_record_options.xml b/packages/SystemUI/res/layout/screen_record_options.xml
index d9f4b7961636..8916e427a1d5 100644
--- a/packages/SystemUI/res/layout/screen_record_options.xml
+++ b/packages/SystemUI/res/layout/screen_record_options.xml
@@ -47,6 +47,7 @@
android:layout_weight="0"
android:layout_gravity="end"
android:id="@+id/screenrecord_audio_switch"
+ android:contentDescription="@string/screenrecord_audio_label"
style="@style/ScreenRecord.Switch"
android:importantForAccessibility="yes"/>
</LinearLayout>
@@ -79,6 +80,7 @@
android:minWidth="48dp"
android:layout_height="48dp"
android:id="@+id/screenrecord_taps_switch"
+ android:contentDescription="@string/screenrecord_taps_label"
style="@style/ScreenRecord.Switch"
android:importantForAccessibility="yes"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 0620355c2f98..e124aa0eda37 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -119,9 +119,8 @@
<!-- Keyboard shortcuts colors -->
<color name="ksh_application_group_color">#fff44336</color>
- <color name="ksh_key_item_color">@color/material_grey_600</color>
- <color name="ksh_key_item_background">@color/material_grey_100</color>
- <color name="ksh_key_item_new_background">@color/transparent</color>
+ <color name="ksh_key_item_color">?androidprv:attr/materialColorOnSurfaceVariant</color>
+ <color name="ksh_key_item_background">?androidprv:attr/materialColorSurfaceContainerHighest</color>
<color name="instant_apps_color">#ff4d5a64</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 30392d2c9d85..03960d522653 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -940,8 +940,11 @@
<!-- Keyboard shortcuts helper -->
<dimen name="ksh_layout_width">@dimen/match_parent</dimen>
<dimen name="ksh_item_text_size">14sp</dimen>
- <dimen name="ksh_item_padding">4dp</dimen>
+ <dimen name="ksh_item_padding">0dp</dimen>
<dimen name="ksh_item_margin_start">4dp</dimen>
+ <dimen name="ksh_icon_scaled_size">18dp</dimen>
+ <dimen name="ksh_key_view_padding_vertical">4dp</dimen>
+ <dimen name="ksh_key_view_padding_horizontal">12dp</dimen>
<!-- The size of corner radius of the arrow in the onboarding toast. -->
<dimen name="recents_onboarding_toast_arrow_corner_radius">2dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index daf6cb3d683d..f49d2a19bcd4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1773,13 +1773,13 @@
<!-- Name used to refer to the "Back" key on the keyboard. -->
<string name="keyboard_key_back">Back</string>
<!-- Name used to refer to the "Up" arrow key on the keyboard. -->
- <string name="keyboard_key_dpad_up">Up</string>
+ <string name="keyboard_key_dpad_up">Up arrow</string>
<!-- Name used to refer to the "Down" arrow key on the keyboard. -->
- <string name="keyboard_key_dpad_down">Down</string>
+ <string name="keyboard_key_dpad_down">Down arrow</string>
<!-- Name used to refer to the "Left" arrow key on the keyboard. -->
- <string name="keyboard_key_dpad_left">Left</string>
+ <string name="keyboard_key_dpad_left">Left arrow</string>
<!-- Name used to refer to the "Right" arrow key on the keyboard. -->
- <string name="keyboard_key_dpad_right">Right</string>
+ <string name="keyboard_key_dpad_right">Right arrow</string>
<!-- Name used to refer to the "Center" arrow key on the keyboard. -->
<string name="keyboard_key_dpad_center">Center</string>
<!-- Name used to refer to the "Tab" key on the keyboard. -->
@@ -1834,9 +1834,11 @@
<string name="keyboard_shortcut_group_system_shortcuts_helper">Keyboard Shortcuts</string>
<!-- User visible title for the keyboard shortcut that switches to the next hardware keyboard layout. -->
<string name="keyboard_shortcut_group_system_switch_input">Switch keyboard layout</string>
+ <!-- User visible string that joins different shortcuts in a list, e.g. shortcut1 "or" shortcut2 "or" ... -->
+ <string name="keyboard_shortcut_join">or</string>
- <!-- Content description for the clear text button in shortcut search list. [CHAR LIMIT=NONE] -->
- <string name="keyboard_shortcut_clear_text">Clear text</string>
+ <!-- Content description for the clear search button in shortcut search list. [CHAR LIMIT=NONE] -->
+ <string name="keyboard_shortcut_clear_text">Clear search query</string>
<!-- The title for keyboard shortcut search list [CHAR LIMIT=25] -->
<string name="keyboard_shortcut_search_list_title">Shortcuts</string>
<!-- The hint for keyboard shortcut search list [CHAR LIMIT=25] -->
@@ -1852,52 +1854,63 @@
<!-- The title of current app category in shortcut search list. [CHAR LIMIT=25] -->
<string name="keyboard_shortcut_search_category_current_app">Current app</string>
+ <!-- A11y message when showing keyboard shortcut search results. [CHAR LIMT=NONE] -->
+ <string name="keyboard_shortcut_a11y_show_search_results">Showing search results</string>
+ <!-- A11y message when filtering to "system" keyboard shortcuts. [CHAR LIMT=NONE] -->
+ <string name="keyboard_shortcut_a11y_filter_system">Showing system shortcuts</string>
+ <!-- A11y message when filtering to "input" keyboard shortcuts. [CHAR LIMT=NONE] -->
+ <string name="keyboard_shortcut_a11y_filter_input">Showing input shortcuts</string>
+ <!-- A11y message when filtering to "app opening" keyboard shortcuts. [CHAR LIMT=NONE] -->
+ <string name="keyboard_shortcut_a11y_filter_open_apps">Showing shortcuts that open apps</string>
+ <!-- A11y message when filtering to "current app" keyboard shortcuts. [CHAR LIMT=NONE] -->
+ <string name="keyboard_shortcut_a11y_filter_current_app">Showing shortcuts for the current app</string>
+
<!-- User visible title for the keyboard shortcut that triggers the notification shade. [CHAR LIMIT=70] -->
- <string name="group_system_access_notification_shade">Access notification shade</string>
+ <string name="group_system_access_notification_shade">View notifications</string>
<!-- User visible title for the keyboard shortcut that takes a full screenshot. [CHAR LIMIT=70] -->
- <string name="group_system_full_screenshot">Take a full screenshot</string>
+ <string name="group_system_full_screenshot">Take screenshot</string>
<!-- User visible title for the keyboard shortcut that access list of system / apps shortcuts. [CHAR LIMIT=70] -->
- <string name="group_system_access_system_app_shortcuts">Access list of system / apps shortcuts</string>
+ <string name="group_system_access_system_app_shortcuts">Show shortcuts</string>
<!-- User visible title for the keyboard shortcut that goes back to previous state. [CHAR LIMIT=70] -->
- <string name="group_system_go_back">Back: go back to previous state (back button)</string>
+ <string name="group_system_go_back">Go back</string>
<!-- User visible title for the keyboard shortcut that takes the user to the home screen. [CHAR LIMIT=70] -->
- <string name="group_system_access_home_screen">Access home screen</string>
+ <string name="group_system_access_home_screen">Go to home screen</string>
<!-- User visible title for the keyboard shortcut that triggers overview of open apps. [CHAR LIMIT=70] -->
- <string name="group_system_overview_open_apps">Overview of open apps</string>
+ <string name="group_system_overview_open_apps">View recent apps</string>
<!-- User visible title for the keyboard shortcut that cycles through recent apps (forward). [CHAR LIMIT=70] -->
- <string name="group_system_cycle_forward">Cycle through recent apps (forward)</string>
+ <string name="group_system_cycle_forward">Cycle forward through recent apps</string>
<!-- User visible title for the keyboard shortcut that cycles through recent apps (back). [CHAR LIMIT=70] -->
- <string name="group_system_cycle_back">Cycle through recent apps (back)</string>
+ <string name="group_system_cycle_back">Cycle backward through recent apps</string>
<!-- User visible title for the keyboard shortcut that accesses list of all apps and search. [CHAR LIMIT=70] -->
- <string name="group_system_access_all_apps_search">Access list of all apps and search (i.e. Search/Launcher)</string>
+ <string name="group_system_access_all_apps_search">Open apps list</string>
<!-- User visible title for the keyboard shortcut that hides and (re)showes taskbar. [CHAR LIMIT=70] -->
- <string name="group_system_hide_reshow_taskbar">Hide and (re)show taskbar</string>
- <!-- User visible title for the keyboard shortcut that accesses system settings. [CHAR LIMIT=70] -->
- <string name="group_system_access_system_settings">Access system settings</string>
- <!-- User visible title for the keyboard shortcut that accesses Google Assistant. [CHAR LIMIT=70] -->
- <string name="group_system_access_google_assistant">Access Google Assistant</string>
+ <string name="group_system_hide_reshow_taskbar">Show taskbar</string>
+ <!-- User visible title for the keyboard shortcut that accesses [system] settings. [CHAR LIMIT=70] -->
+ <string name="group_system_access_system_settings">Open settings</string>
+ <!-- User visible title for the keyboard shortcut that accesses Assistant app. [CHAR LIMIT=70] -->
+ <string name="group_system_access_google_assistant">Open assistant</string>
<!-- User visible title for the keyboard shortcut that locks screen. [CHAR LIMIT=70] -->
<string name="group_system_lock_screen">Lock screen</string>
<!-- User visible title for the keyboard shortcut that pulls up Notes app for quick memo. [CHAR LIMIT=70] -->
- <string name="group_system_quick_memo">Pull up Notes app for quick memo</string>
+ <string name="group_system_quick_memo">Open notes</string>
<!-- User visible title for the system multitasking keyboard shortcuts list. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_system_multitasking">System multitasking</string>
<!-- User visible title for the keyboard shortcut that enters split screen with current app to RHS [CHAR LIMIT=70] -->
- <string name="system_multitasking_rhs">Enter Split screen with current app to RHS</string>
+ <string name="system_multitasking_rhs">Enter split screen with current app to RHS</string>
<!-- User visible title for the keyboard shortcut that enters split screen with current app to LHS [CHAR LIMIT=70] -->
- <string name="system_multitasking_lhs">Enter Split screen with current app to LHS</string>
+ <string name="system_multitasking_lhs">Enter split screen with current app to LHS</string>
<!-- User visible title for the keyboard shortcut that switches from split screen to full screen [CHAR LIMIT=70] -->
- <string name="system_multitasking_full_screen">Switch from Split screen to full screen</string>
+ <string name="system_multitasking_full_screen">Switch from split screen to full screen</string>
<!-- User visible title for the keyboard shortcut that replaces an app from one to another during split screen [CHAR LIMIT=70] -->
- <string name="system_multitasking_replace">During Split screen: replace an app from one to another</string>
+ <string name="system_multitasking_replace">During split screen: replace an app from one to another</string>
<!-- User visible title for the input keyboard shortcuts list. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_input">Input</string>
<!-- User visible title for the keyboard shortcut that switches input language (next language). [CHAR LIMIT=70] -->
- <string name="input_switch_input_language_next">Switch input language (next language)</string>
+ <string name="input_switch_input_language_next">Switch to next language</string>
<!-- User visible title for the keyboard shortcut that switches input language (previous language). [CHAR LIMIT=70] -->
- <string name="input_switch_input_language_previous">Switch input language (previous language)</string>
+ <string name="input_switch_input_language_previous">Switch to previous language</string>
<!-- User visible title for the keyboard shortcut that accesses emoji. [CHAR LIMIT=70] -->
<string name="input_access_emoji">Access emoji</string>
<!-- User visible title for the keyboard shortcut that accesses voice typing. [CHAR LIMIT=70] -->
@@ -1905,14 +1918,14 @@
<!-- User visible title for the system-wide applications keyboard shortcuts list. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications">Applications</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the assist app. [CHAR LIMIT=70] -->
- <string name="keyboard_shortcut_group_applications_assist">Assist</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the assistant app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_assist">Assistant</string>
<!-- User visible title for the keyboard shortcut that takes the user to the browser app. [CHAR LIMIT=70] -->
- <string name="keyboard_shortcut_group_applications_browser">Browser (Chrome as default)</string>
+ <string name="keyboard_shortcut_group_applications_browser">Browser</string>
<!-- User visible title for the keyboard shortcut that takes the user to the contacts app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_contacts">Contacts</string>
<!-- User visible title for the keyboard shortcut that takes the user to the email app. [CHAR LIMIT=70] -->
- <string name="keyboard_shortcut_group_applications_email">Email (Gmail as default)</string>
+ <string name="keyboard_shortcut_group_applications_email">Email</string>
<!-- User visible title for the keyboard shortcut that takes the user to the SMS messaging app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_sms">SMS</string>
<!-- User visible title for the keyboard shortcut that takes the user to the music app. [CHAR LIMIT=70] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index befee2b3eeb7..c48dd9d2f68b 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -420,6 +420,11 @@
<!-- Cannot double inherit. Use Theme.SystemUI.QuickSettings in code to match -->
<style name="BrightnessDialog" parent="@android:style/Theme.DeviceDefault.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowAnimationStyle">@style/Animation.BrightnessDialog</item>
+ </style>
+
+ <style name="Animation.BrightnessDialog">
+ <item name="android:windowExitAnimation">@anim/instant_fade_out</item>
</style>
<style name="Theme.SystemUI.ContrastDialog" parent="@android:style/Theme.DeviceDefault.Dialog">
@@ -1513,10 +1518,6 @@
<item name="android:background">?android:attr/dividerHorizontal</item>
</style>
- <style name="ShortcutItemBackground">
- <item name="android:background">@color/ksh_key_item_new_background</item>
- </style>
-
<style name="LongPressLockScreenAnimation">
<item name="android:windowEnterAnimation">@anim/long_press_lock_screen_popup_enter</item>
<item name="android:windowExitAnimation">@anim/long_press_lock_screen_popup_exit</item>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
index 050b399fd3e8..ff23837703b5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
@@ -30,13 +30,16 @@ import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLoggin
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
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 java.util.concurrent.Executor
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn
/** Repository for the current state of the display */
@@ -66,7 +69,8 @@ constructor(
deviceStateManager: DeviceStateManager,
displayManager: DisplayManager,
@Main handler: Handler,
- @Main mainExecutor: Executor
+ @Background backgroundExecutor: Executor,
+ @Background backgroundDispatcher: CoroutineDispatcher,
) : DisplayStateRepository {
override val isReverseDefaultRotation =
context.resources.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)
@@ -94,9 +98,10 @@ constructor(
}
sendRearDisplayStateUpdate(false)
- deviceStateManager.registerCallback(mainExecutor, callback)
+ deviceStateManager.registerCallback(backgroundExecutor, callback)
awaitClose { deviceStateManager.unregisterCallback(callback) }
}
+ .flowOn(backgroundDispatcher)
.stateIn(
applicationScope,
started = SharingStarted.Eagerly,
@@ -137,6 +142,7 @@ constructor(
)
awaitClose { displayManager.unregisterDisplayListener(callback) }
}
+ .flowOn(backgroundDispatcher)
.stateIn(
applicationScope,
started = SharingStarted.Eagerly,
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
index 7bca86e2e8fb..12be32c54b22 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
@@ -31,8 +31,10 @@ import com.android.systemui.statusbar.policy.onThemeChanged
import com.android.systemui.util.kotlin.emitOnStart
import com.android.systemui.util.view.bindLatest
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -95,7 +97,8 @@ constructor(
* call [onInflate] on the resulting view each time. Disposes of the [DisposableHandle] returned by
* [onInflate] when done.
*
- * This never completes unless cancelled, it just suspends and waits for updates.
+ * This never completes unless cancelled, it just suspends and waits for updates. It runs on a
+ * background thread using [backgroundDispatcher].
*
* For parameters [resource], [root] and [attachToRoot], see [LayoutInflater.inflate].
*
@@ -105,7 +108,7 @@ constructor(
* ```
* parentView.repeatWhenAttached {
* configurationState
- * .reinflateOnChange(
+ * .reinflateAndBindLatest(
* R.layout.my_layout,
* parentView,
* attachToRoot = false,
@@ -124,7 +127,10 @@ suspend fun <T : View> ConfigurationState.reinflateAndBindLatest(
@LayoutRes resource: Int,
root: ViewGroup?,
attachToRoot: Boolean,
+ backgroundDispatcher: CoroutineDispatcher,
onInflate: (T) -> DisposableHandle?,
) {
- inflateLayout<T>(resource, root, attachToRoot).bindLatest(onInflate)
+ inflateLayout<T>(resource, root, attachToRoot)
+ .flowOn(backgroundDispatcher)
+ .bindLatest(onInflate)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 2b1cdc2ff026..33dd3d9bea16 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -647,7 +647,7 @@ public class KeyguardService extends Service {
public void dismissKeyguardToLaunch(Intent intentToLaunch) {
trace("dismissKeyguardToLaunch");
checkPermission();
- mKeyguardViewMediator.dismissKeyguardToLaunch(intentToLaunch);
+ Slog.d(TAG, "Ignoring dismissKeyguardToLaunch " + intentToLaunch);
}
@Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 53ec3dead6c5..30090874a480 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -248,7 +248,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private static final int SHOW = 1;
private static final int HIDE = 2;
private static final int RESET = 3;
- private static final int VERIFY_UNLOCK = 4;
private static final int NOTIFY_FINISHED_GOING_TO_SLEEP = 5;
private static final int KEYGUARD_DONE = 7;
private static final int KEYGUARD_DONE_DRAWING = 8;
@@ -2316,15 +2315,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mHandler.sendMessage(msg);
}
- /**
- * Send message to keyguard telling it to verify unlock
- * @see #handleVerifyUnlock()
- */
- private void verifyUnlockLocked() {
- if (DEBUG) Log.d(TAG, "verifyUnlockLocked");
- mHandler.sendEmptyMessage(VERIFY_UNLOCK);
- }
-
private void notifyStartedGoingToSleep() {
if (DEBUG) Log.d(TAG, "notifyStartedGoingToSleep");
mHandler.sendEmptyMessage(NOTIFY_STARTED_GOING_TO_SLEEP);
@@ -2498,12 +2488,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
message = "RESET";
handleReset(msg.arg1 != 0);
break;
- case VERIFY_UNLOCK:
- message = "VERIFY_UNLOCK";
- Trace.beginSection("KeyguardViewMediator#handleMessage VERIFY_UNLOCK");
- handleVerifyUnlock();
- Trace.endSection();
- break;
case NOTIFY_STARTED_GOING_TO_SLEEP:
message = "NOTIFY_STARTED_GOING_TO_SLEEP";
handleNotifyStartedGoingToSleep();
@@ -3435,20 +3419,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
scheduleNonStrongBiometricIdleTimeout();
}
- /**
- * Handle message sent by {@link #verifyUnlock}
- * @see #VERIFY_UNLOCK
- */
- private void handleVerifyUnlock() {
- Trace.beginSection("KeyguardViewMediator#handleVerifyUnlock");
- synchronized (KeyguardViewMediator.this) {
- if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
- setShowingLocked(true);
- mKeyguardViewControllerLazy.get().dismissAndCollapse();
- }
- Trace.endSection();
- }
-
private void handleNotifyStartedGoingToSleep() {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleNotifyStartedGoingToSleep");
@@ -3606,10 +3576,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// do nothing
}
- public void dismissKeyguardToLaunch(Intent intentToLaunch) {
- // do nothing
- }
-
public void onSystemKeyPressed(int keycode) {
// do nothing
}
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 8ef26621362f..36412e31e7c0 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
@@ -253,7 +253,7 @@ constructor(
Pair(isAuthenticated.isFalse(), "faceNotAuthenticated"),
)
.andAllFlows("canFaceAuthRun", faceAuthLog)
- .flowOn(mainDispatcher)
+ .flowOn(backgroundDispatcher)
.stateIn(applicationScope, SharingStarted.Eagerly, false)
// Face detection can run only when lockscreen bypass is enabled
@@ -280,7 +280,7 @@ constructor(
)
)
.andAllFlows("canFaceDetectRun", faceDetectLog)
- .flowOn(mainDispatcher)
+ .flowOn(backgroundDispatcher)
.stateIn(applicationScope, SharingStarted.Eagerly, false)
observeFaceAuthGatingChecks()
observeFaceDetectGatingChecks()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
index 9bec30052476..96386f3dc596 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
@@ -26,6 +26,7 @@ import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLoggin
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus
@@ -33,11 +34,13 @@ import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatu
import com.android.systemui.keyguard.shared.model.HelpFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn
/** Encapsulates state about device entry fingerprint auth mechanism. */
@@ -74,6 +77,7 @@ constructor(
val authController: AuthController,
val keyguardUpdateMonitor: KeyguardUpdateMonitor,
@Application scope: CoroutineScope,
+ @Main private val mainDispatcher: CoroutineDispatcher,
) : DeviceEntryFingerprintAuthRepository {
override val availableFpSensorType: Flow<BiometricType?>
@@ -137,30 +141,34 @@ constructor(
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
override val isRunning: Flow<Boolean>
- get() = conflatedCallbackFlow {
- val callback =
- object : KeyguardUpdateMonitorCallback() {
- override fun onBiometricRunningStateChanged(
- running: Boolean,
- biometricSourceType: BiometricSourceType?
- ) {
- if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
- trySendWithFailureLogging(
- running,
- TAG,
- "Fingerprint running state changed"
- )
+ get() =
+ conflatedCallbackFlow {
+ val callback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricRunningStateChanged(
+ running: Boolean,
+ biometricSourceType: BiometricSourceType?
+ ) {
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
+ trySendWithFailureLogging(
+ running,
+ TAG,
+ "Fingerprint running state changed"
+ )
+ }
+ }
}
- }
+ keyguardUpdateMonitor.registerCallback(callback)
+ trySendWithFailureLogging(
+ keyguardUpdateMonitor.isFingerprintDetectionRunning,
+ TAG,
+ "Initial fingerprint running state"
+ )
+ awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
- keyguardUpdateMonitor.registerCallback(callback)
- trySendWithFailureLogging(
- keyguardUpdateMonitor.isFingerprintDetectionRunning,
- TAG,
- "Initial fingerprint running state"
- )
- awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
- }
+ .flowOn(
+ mainDispatcher
+ ) // keyguardUpdateMonitor requires registration on main thread.
override val authenticationStatus: Flow<FingerprintAuthenticationStatus>
get() = conflatedCallbackFlow {
@@ -171,7 +179,6 @@ constructor(
biometricSourceType: BiometricSourceType,
isStrongBiometric: Boolean,
) {
-
sendUpdateIfFingerprint(
biometricSourceType,
SuccessFingerprintAuthenticationStatus(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt
index adb1e01d0d00..7c430920cb46 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt
@@ -19,11 +19,14 @@ package com.android.systemui.keyguard.data.repository
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.shared.model.DevicePosture
import com.android.systemui.statusbar.policy.DevicePostureController
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOn
/** Provide current device posture state. */
interface DevicePostureRepository {
@@ -34,23 +37,28 @@ interface DevicePostureRepository {
@SysUISingleton
class DevicePostureRepositoryImpl
@Inject
-constructor(private val postureController: DevicePostureController) : DevicePostureRepository {
+constructor(
+ private val postureController: DevicePostureController,
+ @Main private val mainDispatcher: CoroutineDispatcher
+) : DevicePostureRepository {
override val currentDevicePosture: Flow<DevicePosture>
- get() = conflatedCallbackFlow {
- val sendPostureUpdate = { posture: Int ->
- val currentDevicePosture = DevicePosture.toPosture(posture)
- trySendWithFailureLogging(
- currentDevicePosture,
- TAG,
- "Error sending posture update to $currentDevicePosture"
- )
- }
- val callback = DevicePostureController.Callback { sendPostureUpdate(it) }
- postureController.addCallback(callback)
- sendPostureUpdate(postureController.devicePosture)
+ get() =
+ conflatedCallbackFlow {
+ val sendPostureUpdate = { posture: Int ->
+ val currentDevicePosture = DevicePosture.toPosture(posture)
+ trySendWithFailureLogging(
+ currentDevicePosture,
+ TAG,
+ "Error sending posture update to $currentDevicePosture"
+ )
+ }
+ val callback = DevicePostureController.Callback { sendPostureUpdate(it) }
+ postureController.addCallback(callback)
+ sendPostureUpdate(postureController.devicePosture)
- awaitClose { postureController.removeCallback(callback) }
- }
+ awaitClose { postureController.removeCallback(callback) }
+ }
+ .flowOn(mainDispatcher) // DevicePostureController requirement
companion object {
const val TAG = "PostureRepositoryImpl"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 4da48f697b0f..706aba3c0505 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -302,4 +302,11 @@ constructor(
fun isFinishedInState(state: KeyguardState): Flow<Boolean> {
return finishedKeyguardState.map { it == state }.distinctUntilChanged()
}
+
+ /**
+ * Whether we've FINISHED a transition to a state that matches the given predicate. Consider
+ * using [isFinishedInStateWhere] whenever possible instead
+ */
+ fun isFinishedInStateWhereValue(stateMatcher: (KeyguardState) -> Boolean) =
+ stateMatcher(finishedKeyguardState.replayCache.last())
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 0c5a14f5720a..48f432e6a6ea 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -58,8 +58,8 @@ import androidx.core.graphics.drawable.IconCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.util.concurrent.Executor;
@@ -85,6 +85,13 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
final MediaOutputController mMediaOutputController;
final BroadcastSender mBroadcastSender;
+ /**
+ * Signals whether the dialog should NOT show app-related metadata.
+ *
+ * <p>A metadata-less dialog hides the title, subtitle, and app icon in the header.
+ */
+ private final boolean mIncludePlaybackAndAppMetadata;
+
@VisibleForTesting
View mDialogView;
private TextView mHeaderTitle;
@@ -210,8 +217,11 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
}
- public MediaOutputBaseDialog(Context context, BroadcastSender broadcastSender,
- MediaOutputController mediaOutputController) {
+ public MediaOutputBaseDialog(
+ Context context,
+ BroadcastSender broadcastSender,
+ MediaOutputController mediaOutputController,
+ boolean includePlaybackAndAppMetadata) {
super(context, R.style.Theme_SystemUI_Dialog_Media);
// Save the context that is wrapped with our theme.
@@ -226,6 +236,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mListPaddingTop = mContext.getResources().getDimensionPixelSize(
R.dimen.media_output_dialog_list_padding_top);
mExecutor = Executors.newSingleThreadExecutor();
+ mIncludePlaybackAndAppMetadata = includePlaybackAndAppMetadata;
}
@Override
@@ -354,7 +365,10 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
updateDialogBackgroundColor();
mHeaderIcon.setVisibility(View.GONE);
}
- if (appSourceIcon != null) {
+
+ if (!mIncludePlaybackAndAppMetadata) {
+ mAppResourceIcon.setVisibility(View.GONE);
+ } else if (appSourceIcon != null) {
Icon appIcon = appSourceIcon.toIcon(mContext);
mAppResourceIcon.setColorFilter(mMediaOutputController.getColorItemContent());
mAppResourceIcon.setImageIcon(appIcon);
@@ -373,17 +387,24 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
}
mAppButton.setText(mMediaOutputController.getAppSourceName());
- // Update title and subtitle
- mHeaderTitle.setText(getHeaderText());
- final CharSequence subTitle = getHeaderSubtitle();
- if (TextUtils.isEmpty(subTitle)) {
+
+ if (!mIncludePlaybackAndAppMetadata) {
+ mHeaderTitle.setVisibility(View.GONE);
mHeaderSubtitle.setVisibility(View.GONE);
- mHeaderTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
} else {
- mHeaderSubtitle.setVisibility(View.VISIBLE);
- mHeaderSubtitle.setText(subTitle);
- mHeaderTitle.setGravity(Gravity.NO_GRAVITY);
+ // Update title and subtitle
+ mHeaderTitle.setText(getHeaderText());
+ final CharSequence subTitle = getHeaderSubtitle();
+ if (TextUtils.isEmpty(subTitle)) {
+ mHeaderSubtitle.setVisibility(View.GONE);
+ mHeaderTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
+ } else {
+ mHeaderSubtitle.setVisibility(View.VISIBLE);
+ mHeaderSubtitle.setText(subTitle);
+ mHeaderTitle.setGravity(Gravity.NO_GRAVITY);
+ }
}
+
// Show when remote media session is available or
// when the device supports BT LE audio + media is playing
mStopButton.setVisibility(getStopButtonVisibility());
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index ac64300a6570..8e0191ec330f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -42,12 +42,10 @@ import androidx.annotation.NonNull;
import androidx.core.graphics.drawable.IconCompat;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.settingslib.media.BluetoothMediaDevice;
-import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.qrcode.QrCodeGenerator;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.google.zxing.WriterException;
@@ -237,7 +235,11 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
MediaOutputBroadcastDialog(Context context, boolean aboveStatusbar,
BroadcastSender broadcastSender, MediaOutputController mediaOutputController) {
- super(context, broadcastSender, mediaOutputController);
+ super(
+ context,
+ broadcastSender,
+ mediaOutputController, /* includePlaybackAndAppMetadata */
+ true);
mAdapter = new MediaOutputAdapter(mMediaOutputController);
// TODO(b/226710953): Move the part to MediaOutputBaseDialog for every class
// that extends MediaOutputBaseDialog
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 426a497fa329..375a0ce55ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -78,7 +78,6 @@ import com.android.settingslib.media.InfoMediaManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.utils.ThreadUtils;
-import com.android.systemui.res.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastSender;
@@ -86,6 +85,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.monet.ColorScheme;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -358,7 +358,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
}
Drawable getAppSourceIconFromPackage() {
- if (mPackageName.isEmpty()) {
+ if (TextUtils.isEmpty(mPackageName)) {
return null;
}
try {
@@ -372,7 +372,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
}
String getAppSourceName() {
- if (mPackageName.isEmpty()) {
+ if (TextUtils.isEmpty(mPackageName)) {
return null;
}
final PackageManager packageManager = mContext.getPackageManager();
@@ -391,7 +391,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
}
Intent getAppLaunchIntent() {
- if (mPackageName.isEmpty()) {
+ if (TextUtils.isEmpty(mPackageName)) {
return null;
}
return mContext.getPackageManager().getLaunchIntentForPackage(mPackageName);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index 4640a5d4d801..d40699ca088c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -27,10 +27,10 @@ import androidx.core.graphics.drawable.IconCompat;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.res.R;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.res.R;
/**
* Dialog for media output transferring.
@@ -40,10 +40,15 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
private final DialogLaunchAnimator mDialogLaunchAnimator;
private final UiEventLogger mUiEventLogger;
- MediaOutputDialog(Context context, boolean aboveStatusbar, BroadcastSender broadcastSender,
- MediaOutputController mediaOutputController, DialogLaunchAnimator dialogLaunchAnimator,
- UiEventLogger uiEventLogger) {
- super(context, broadcastSender, mediaOutputController);
+ MediaOutputDialog(
+ Context context,
+ boolean aboveStatusbar,
+ BroadcastSender broadcastSender,
+ MediaOutputController mediaOutputController,
+ DialogLaunchAnimator dialogLaunchAnimator,
+ UiEventLogger uiEventLogger,
+ boolean includePlaybackAndAppMetadata) {
+ super(context, broadcastSender, mediaOutputController, includePlaybackAndAppMetadata);
mDialogLaunchAnimator = dialogLaunchAnimator;
mUiEventLogger = uiEventLogger;
mAdapter = new MediaOutputAdapter(mMediaOutputController);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index 2b38edb3c47e..b04a7a4fd155 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -61,6 +61,19 @@ open class MediaOutputDialogFactory @Inject constructor(
/** Creates a [MediaOutputDialog] for the given package. */
open fun create(packageName: String, aboveStatusBar: Boolean, view: View? = null) {
+ create(packageName, aboveStatusBar, view, includePlaybackAndAppMetadata = true)
+ }
+
+ open fun createDialogForSystemRouting() {
+ create(packageName = null, aboveStatusBar = false, includePlaybackAndAppMetadata = false)
+ }
+
+ private fun create(
+ packageName: String?,
+ aboveStatusBar: Boolean,
+ view: View? = null,
+ includePlaybackAndAppMetadata: Boolean = true
+ ) {
// Dismiss the previous dialog, if any.
mediaOutputDialog?.dismiss()
@@ -71,7 +84,7 @@ open class MediaOutputDialogFactory @Inject constructor(
powerExemptionManager, keyGuardManager, featureFlags, userTracker)
val dialog =
MediaOutputDialog(context, aboveStatusBar, broadcastSender, controller,
- dialogLaunchAnimator, uiEventLogger)
+ dialogLaunchAnimator, uiEventLogger, includePlaybackAndAppMetadata)
mediaOutputDialog = dialog
// Show the dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
index 132bf99c3f62..1002cc3bd3bb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
@@ -19,7 +19,6 @@ package com.android.systemui.media.dialog
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
-import android.text.TextUtils
import android.util.Log
import com.android.settingslib.media.MediaOutputConstants
import javax.inject.Inject
@@ -35,16 +34,16 @@ class MediaOutputDialogReceiver @Inject constructor(
private val mediaOutputBroadcastDialogFactory: MediaOutputBroadcastDialogFactory
) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
- when {
- TextUtils.equals(
- MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG, intent.action) -> {
+ when (intent.action) {
+ MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG -> {
val packageName: String? =
intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME)
launchMediaOutputDialogIfPossible(packageName)
}
- TextUtils.equals(
- MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG,
- intent.action) -> {
+ MediaOutputConstants.ACTION_LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG -> {
+ mediaOutputDialogFactory.createDialogForSystemRouting()
+ }
+ MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG -> {
val packageName: String? =
intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME)
launchMediaOutputBroadcastDialogIfPossible(packageName)
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
index 654fffe89471..1983a670b5a8 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
@@ -24,6 +24,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewStub
import android.view.WindowManager
+import android.view.accessibility.AccessibilityNodeInfo
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.ImageView
@@ -106,6 +107,19 @@ abstract class BaseMediaProjectionPermissionDialogDelegate<T : AlertDialog>(
screenShareModeSpinner = dialog.requireViewById(R.id.screen_share_mode_spinner)
screenShareModeSpinner.adapter = adapter
screenShareModeSpinner.onItemSelectedListener = this
+
+ // disable redundant Touch & Hold accessibility action for Switch Access
+ screenShareModeSpinner.accessibilityDelegate =
+ object : View.AccessibilityDelegate() {
+ override fun onInitializeAccessibilityNodeInfo(
+ host: View,
+ info: AccessibilityNodeInfo
+ ) {
+ info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK)
+ super.onInitializeAccessibilityNodeInfo(host, info)
+ }
+ }
+ screenShareModeSpinner.isLongClickable = false
}
override fun onItemSelected(adapterView: AdapterView<*>?, view: View, pos: Int, id: Long) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index f13add9b62b6..e2e94dae900a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -72,6 +72,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.Trace;
import android.provider.DeviceConfig;
import android.telecom.TelecomManager;
import android.text.TextUtils;
@@ -736,17 +737,27 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
}
public void destroyView() {
- setAutoHideController(/* autoHideController */ null);
- mCommandQueue.removeCallback(this);
- mWindowManager.removeViewImmediate(mView.getRootView());
- mNavigationModeController.removeListener(mModeChangedListener);
- mEdgeBackGestureHandler.setStateChangeCallback(null);
+ Trace.beginSection("NavigationBar#destroyView");
+ try {
+ setAutoHideController(/* autoHideController */ null);
+ mCommandQueue.removeCallback(this);
+ Trace.beginSection("NavigationBar#removeViewImmediate");
+ try {
+ mWindowManager.removeViewImmediate(mView.getRootView());
+ } finally {
+ Trace.endSection();
+ }
+ mNavigationModeController.removeListener(mModeChangedListener);
+ mEdgeBackGestureHandler.setStateChangeCallback(null);
- mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
- mNotificationShadeDepthController.removeListener(mDepthListener);
+ mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+ mNotificationShadeDepthController.removeListener(mDepthListener);
- mDeviceConfigProxy.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
- mTaskStackChangeListeners.unregisterTaskStackListener(mTaskStackListener);
+ mDeviceConfigProxy.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
+ mTaskStackChangeListeners.unregisterTaskStackListener(mTaskStackListener);
+ } finally {
+ Trace.endSection();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 3b32313e76a0..8d1ff98a5bba 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -46,6 +46,7 @@ import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.Trace;
import android.util.Log;
import android.view.Display;
import android.view.View;
@@ -229,28 +230,34 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
}
public void init(int displayId) {
- if (mInitialized) {
- return;
+ Trace.beginSection("TaskbarDelegate#init");
+ try {
+ if (mInitialized) {
+ return;
+ }
+ mDisplayId = displayId;
+ parseCurrentSysuiState();
+ mCommandQueue.addCallback(this);
+ mOverviewProxyService.addCallback(this);
+ onNavigationModeChanged(mNavigationModeController.addListener(this));
+ mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+ // Initialize component callback
+ Display display = mDisplayManager.getDisplay(displayId);
+ mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null);
+ mScreenPinningNotify = new ScreenPinningNotify(mWindowContext);
+ // Set initial state for any listeners
+ updateSysuiFlags();
+ mAutoHideController.setNavigationBar(mAutoHideUiElement);
+ mLightBarController.setNavigationBar(mLightBarTransitionsController);
+ mPipOptional.ifPresent(this::addPipExclusionBoundsChangeListener);
+ mEdgeBackGestureHandler.setBackAnimation(mBackAnimation);
+ mEdgeBackGestureHandler.onConfigurationChanged(
+ mContext.getResources().getConfiguration());
+ mTaskStackChangeListeners.registerTaskStackListener(mTaskStackListener);
+ mInitialized = true;
+ } finally {
+ Trace.endSection();
}
- mDisplayId = displayId;
- parseCurrentSysuiState();
- mCommandQueue.addCallback(this);
- mOverviewProxyService.addCallback(this);
- onNavigationModeChanged(mNavigationModeController.addListener(this));
- mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
- // Initialize component callback
- Display display = mDisplayManager.getDisplay(displayId);
- mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null);
- mScreenPinningNotify = new ScreenPinningNotify(mWindowContext);
- // Set initial state for any listeners
- updateSysuiFlags();
- mAutoHideController.setNavigationBar(mAutoHideUiElement);
- mLightBarController.setNavigationBar(mLightBarTransitionsController);
- mPipOptional.ifPresent(this::addPipExclusionBoundsChangeListener);
- mEdgeBackGestureHandler.setBackAnimation(mBackAnimation);
- mEdgeBackGestureHandler.onConfigurationChanged(mContext.getResources().getConfiguration());
- mTaskStackChangeListeners.registerTaskStackListener(mTaskStackListener);
- mInitialized = true;
}
public void destroy() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 3dfd2925a1b2..9846f4b6c980 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -578,10 +578,15 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
* @see NavigationModeController.ModeChangedListener#onNavigationModeChanged
*/
public void onNavigationModeChanged(int mode) {
- mUsingThreeButtonNav = QuickStepContract.isLegacyMode(mode);
- mInGestureNavMode = QuickStepContract.isGesturalMode(mode);
- updateIsEnabled();
- updateCurrentUserResources();
+ Trace.beginSection("EdgeBackGestureHandler#onNavigationModeChanged");
+ try {
+ mUsingThreeButtonNav = QuickStepContract.isLegacyMode(mode);
+ mInGestureNavMode = QuickStepContract.isGesturalMode(mode);
+ updateIsEnabled();
+ updateCurrentUserResources();
+ } finally {
+ Trace.endSection();
+ }
}
public void onNavBarTransientStateChanged(boolean isTransient) {
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index d9a8080a1e83..270bfbe4274d 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -37,9 +37,10 @@ import android.os.UserManager
import android.provider.Settings
import android.widget.Toast
import androidx.annotation.VisibleForTesting
-import com.android.systemui.res.R
+import com.android.app.tracing.TraceUtils.Companion.launch
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled
import com.android.systemui.log.DebugLogger.debugLog
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
@@ -47,6 +48,7 @@ import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON
import com.android.systemui.notetask.NoteTaskRoleManagerExt.createNoteShortcutInfoAsUser
import com.android.systemui.notetask.NoteTaskRoleManagerExt.getDefaultRoleHolderAsUser
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
+import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.system.ActivityManagerKt.isInForeground
import com.android.systemui.util.settings.SecureSettings
@@ -54,8 +56,8 @@ import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.Bubbles.BubbleExpandListener
import java.util.concurrent.atomic.AtomicReference
import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
/**
* Entry point for creating and managing note.
@@ -81,7 +83,8 @@ constructor(
private val devicePolicyManager: DevicePolicyManager,
private val userTracker: UserTracker,
private val secureSettings: SecureSettings,
- @Application private val applicationScope: CoroutineScope
+ @Application private val applicationScope: CoroutineScope,
+ @Background private val bgCoroutineContext: CoroutineContext
) {
@VisibleForTesting val infoReference = AtomicReference<NoteTaskInfo?>()
@@ -172,7 +175,9 @@ constructor(
) {
if (!isEnabled) return
- applicationScope.launch { awaitShowNoteTaskAsUser(entryPoint, user) }
+ applicationScope.launch("$TAG#showNoteTaskAsUser") {
+ awaitShowNoteTaskAsUser(entryPoint, user)
+ }
}
private suspend fun awaitShowNoteTaskAsUser(
@@ -337,7 +342,7 @@ constructor(
@InternalNoteTaskApi
fun launchUpdateNoteTaskAsUser(user: UserHandle) {
- applicationScope.launch {
+ applicationScope.launch("$TAG#launchUpdateNoteTaskAsUser", bgCoroutineContext) {
if (!userManager.isUserUnlocked(user)) {
debugLog { "updateNoteTaskAsUserInternal call but user locked: user=$user" }
return@launch
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index f8e01590d368..456520051f58 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -45,6 +45,7 @@ import android.widget.LinearLayout
import android.widget.Switch
import android.widget.TextView
import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.traceSection
import com.android.settingslib.Utils
import com.android.systemui.FontSizeUtils
import com.android.systemui.animation.LaunchableView
@@ -707,7 +708,7 @@ open class QSTileViewImpl @JvmOverloads constructor(
inner class StateChangeRunnable(private val state: QSTile.State) : Runnable {
override fun run() {
- handleStateChanged(state)
+ traceSection("QSTileViewImpl#handleStateChanged") { handleStateChanged(state) }
}
// We want all instances of this runnable to be equal to each other, so they can be used to
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
index 3afbd7c0d4ec..e8623f9f7664 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
@@ -101,7 +101,10 @@ constructor(
override fun addCallback(callback: QSTile.Callback?) {
callback ?: return
- synchronized(callbacks) { callbacks.add(callback) }
+ synchronized(callbacks) {
+ callbacks.add(callback)
+ state?.let(callback::onStateChanged)
+ }
}
override fun removeCallback(callback: QSTile.Callback?) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
index e57a0fddc936..3f6c58d73346 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.screenrecord
+import android.annotation.SuppressLint
import android.app.Activity
import android.app.PendingIntent
import android.content.Intent
@@ -23,6 +24,7 @@ import android.os.Handler
import android.os.Looper
import android.os.ResultReceiver
import android.os.UserHandle
+import android.view.MotionEvent.ACTION_MOVE
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
@@ -102,11 +104,19 @@ class ScreenRecordPermissionDialogDelegate(
@LayoutRes override fun getOptionsViewLayoutId(): Int = R.layout.screen_record_options
+ @SuppressLint("ClickableViewAccessibility")
private fun initRecordOptionsView() {
audioSwitch = dialog.requireViewById(R.id.screenrecord_audio_switch)
tapsSwitch = dialog.requireViewById(R.id.screenrecord_taps_switch)
+
+ // Add these listeners so that the switch only responds to movement
+ // within its target region, to meet accessibility requirements
+ audioSwitch.setOnTouchListener { _, event -> event.action == ACTION_MOVE }
+ tapsSwitch.setOnTouchListener { _, event -> event.action == ACTION_MOVE }
+
tapsView = dialog.requireViewById(R.id.show_taps)
updateTapsViewVisibility()
+
options = dialog.requireViewById(R.id.screen_recording_options)
val a: ArrayAdapter<*> =
ScreenRecordingAdapter(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index c925010ef4d5..67ec03fc3d0a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1302,6 +1302,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
@Override
public void updateResources() {
+ Trace.beginSection("NSSLC#updateResources");
final boolean newSplitShadeEnabled =
mSplitShadeStateController.shouldUseSplitNotificationShade(mResources);
final boolean splitShadeChanged = mSplitShadeEnabled != newSplitShadeEnabled;
@@ -1318,6 +1319,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mSplitShadeFullTransitionDistance =
mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance);
+ Trace.endSection();
}
private void onSplitShadeEnabledChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
index 4a5089770b05..1b096b592a4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -29,8 +29,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
+import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.hardware.input.InputManagerGlobal;
@@ -119,7 +118,6 @@ public final class KeyboardShortcutListSearch {
private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
private final SparseArray<String> mModifierNames = new SparseArray<>();
- private final SparseArray<Drawable> mSpecialCharacterDrawables = new SparseArray<>();
private final SparseArray<Drawable> mModifierDrawables = new SparseArray<>();
// Ordered list of modifiers that are supported. All values in this array must exist in
// mModifierNames.
@@ -146,7 +144,7 @@ public final class KeyboardShortcutListSearch {
} else {
this.mWindowManager = mContext.getSystemService(WindowManager.class);
}
- loadResources(context);
+ loadResources(this.mContext);
createHardcodedShortcuts();
}
@@ -287,7 +285,7 @@ public final class KeyboardShortcutListSearch {
mSpecialCharacterNames.put(
KeyEvent.KEYCODE_NUM_LOCK, context.getString(R.string.keyboard_key_num_lock));
mSpecialCharacterNames.put(KeyEvent.KEYCODE_MINUS, "-");
- mSpecialCharacterNames.put(KeyEvent.KEYCODE_GRAVE, "~");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_GRAVE, "`");
mSpecialCharacterNames.put(KeyEvent.KEYCODE_EQUALS, "=");
mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_0,
@@ -350,19 +348,6 @@ public final class KeyboardShortcutListSearch {
mModifierNames.put(KeyEvent.META_SYM_ON, "Sym");
mModifierNames.put(KeyEvent.META_FUNCTION_ON, "Fn");
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_DEL, context.getDrawable(R.drawable.ic_ksh_key_backspace));
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_ENTER, context.getDrawable(R.drawable.ic_ksh_key_enter));
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_DPAD_UP, context.getDrawable(R.drawable.ic_ksh_key_up));
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_DPAD_RIGHT, context.getDrawable(R.drawable.ic_ksh_key_right));
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_DPAD_DOWN, context.getDrawable(R.drawable.ic_ksh_key_down));
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_DPAD_LEFT, context.getDrawable(R.drawable.ic_ksh_key_left));
-
mModifierDrawables.put(
KeyEvent.META_META_ON, context.getDrawable(R.drawable.ic_ksh_key_meta));
}
@@ -508,7 +493,7 @@ public final class KeyboardShortcutListSearch {
Arrays.asList(
Pair.create(KeyEvent.KEYCODE_SLASH, KeyEvent.META_META_ON))),
/* Back: go back to previous state (back button) */
- /* Meta + ~, Meta + backspace, Meta + left arrow */
+ /* Meta + Grave, Meta + backspace, Meta + left arrow */
new ShortcutKeyGroupMultiMappingInfo(
context.getString(R.string.group_system_go_back),
Arrays.asList(
@@ -826,11 +811,12 @@ public final class KeyboardShortcutListSearch {
new BottomSheetDialog(mContext);
final View keyboardShortcutsView = inflater.inflate(
R.layout.keyboard_shortcuts_search_view, null);
+ LinearLayout shortcutsContainer = keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container);
mNoSearchResults = keyboardShortcutsView.findViewById(R.id.shortcut_search_no_result);
mKeyboardShortcutsBottomSheetDialog.setContentView(keyboardShortcutsView);
setButtonsDefaultStatus(keyboardShortcutsView);
- populateKeyboardShortcutSearchList(
- keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_container));
+ populateKeyboardShortcutSearchList(shortcutsContainer);
// Workaround for solve issue about dialog not full expanded when landscape.
FrameLayout bottomSheet = (FrameLayout)
@@ -880,9 +866,14 @@ public final class KeyboardShortcutListSearch {
@Override
public void afterTextChanged(Editable s) {
mQueryString = s.toString();
- populateKeyboardShortcutSearchList(
- keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_container));
+ populateKeyboardShortcutSearchList(shortcutsContainer);
+ if (mNoSearchResults.getVisibility() == View.VISIBLE) {
+ shortcutsContainer.setAccessibilityPaneTitle(mContext.getString(
+ R.string.keyboard_shortcut_search_list_no_result));
+ } else if (mSearchEditText.getText().length() > 0) {
+ shortcutsContainer.setAccessibilityPaneTitle(mContext.getString(
+ R.string.keyboard_shortcut_a11y_show_search_results));
+ }
}
@Override
@@ -1034,16 +1025,32 @@ public final class KeyboardShortcutListSearch {
StringDrawableContainer shortcutRepresentation = shortcutKeys.get(k);
if (shortcutRepresentation.mDrawable != null) {
ImageView shortcutKeyIconView = (ImageView) inflater.inflate(
- R.layout.keyboard_shortcuts_key_new_icon_view,
+ R.layout.keyboard_shortcuts_key_icon_view,
shortcutItemsContainer,
false);
- Bitmap bitmap = Bitmap.createBitmap(shortcutKeyIconItemHeightWidth,
- shortcutKeyIconItemHeightWidth, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- shortcutRepresentation.mDrawable.setBounds(0, 0, canvas.getWidth(),
- canvas.getHeight());
- shortcutRepresentation.mDrawable.draw(canvas);
- shortcutKeyIconView.setImageBitmap(bitmap);
+ shortcutKeyIconView.setImageDrawable(
+ shortcutRepresentation.mDrawable);
+ // Once the view has been measured, scale and position the icon in
+ // the center.
+ shortcutKeyIconView.post(() -> {
+ Drawable d = shortcutKeyIconView.getDrawable();
+
+ float newSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.ksh_icon_scaled_size);
+ int viewWidth = shortcutKeyIconView.getWidth();
+ int viewHeight = shortcutKeyIconView.getHeight();
+ float scaleFactor = newSize / d.getIntrinsicWidth();
+ // Assumes that top/bottom and left/right padding are equal.
+ int paddingHorizontal = shortcutKeyIconView.getPaddingLeft();
+ int paddingVertical = shortcutKeyIconView.getPaddingTop();
+
+ Matrix m = new Matrix();
+ m.postScale(scaleFactor, scaleFactor);
+ m.postTranslate(
+ (viewWidth - newSize) / 2 - paddingHorizontal,
+ (viewHeight - newSize) / 2 - paddingVertical);
+ shortcutKeyIconView.setImageMatrix(m);
+ });
shortcutKeyIconView.setImportantForAccessibility(
IMPORTANT_FOR_ACCESSIBILITY_YES);
shortcutKeyIconView.setAccessibilityDelegate(
@@ -1052,7 +1059,7 @@ public final class KeyboardShortcutListSearch {
shortcutItemsContainer.addView(shortcutKeyIconView);
} else if (shortcutRepresentation.mString != null) {
TextView shortcutKeyTextView = (TextView) inflater.inflate(
- R.layout.keyboard_shortcuts_key_new_view,
+ R.layout.keyboard_shortcuts_key_view,
shortcutItemsContainer,
false);
shortcutKeyTextView.setMinimumWidth(shortcutKeyTextItemMinWidth);
@@ -1062,18 +1069,10 @@ public final class KeyboardShortcutListSearch {
shortcutRepresentation.mString));
shortcutItemsContainer.addView(shortcutKeyTextView);
}
-
- if (k < shortcutKeysSize - 1) {
- TextView shortcutKeyTextView = (TextView) inflater.inflate(
- R.layout.keyboard_shortcuts_key_plus_view,
- shortcutItemsContainer,
- false);
- shortcutItemsContainer.addView(shortcutKeyTextView);
- }
}
} else {
TextView shortcutKeyTextView = (TextView) inflater.inflate(
- R.layout.keyboard_shortcuts_key_new_view,
+ R.layout.keyboard_shortcuts_key_view,
shortcutItemsContainer,
false);
shortcutKeyTextView.setMinimumWidth(shortcutKeyTextItemMinWidth);
@@ -1085,7 +1084,7 @@ public final class KeyboardShortcutListSearch {
if (p < keyGroupItemsSize - 1) {
TextView shortcutKeyTextView = (TextView) inflater.inflate(
- R.layout.keyboard_shortcuts_key_vertical_bar_view,
+ R.layout.keyboard_shortcuts_key_separator_view,
shortcutItemsContainer,
false);
shortcutItemsContainer.addView(shortcutKeyTextView);
@@ -1124,9 +1123,6 @@ public final class KeyboardShortcutListSearch {
Drawable shortcutKeyDrawable = null;
if (info.getBaseCharacter() > Character.MIN_VALUE) {
shortcutKeyString = String.valueOf(info.getBaseCharacter());
- } else if (mSpecialCharacterDrawables.get(info.getKeycode()) != null) {
- shortcutKeyDrawable = mSpecialCharacterDrawables.get(info.getKeycode());
- shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
} else if (mSpecialCharacterNames.get(info.getKeycode()) != null) {
shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
} else {
@@ -1232,28 +1228,35 @@ public final class KeyboardShortcutListSearch {
mButtonOpenApps = keyboardShortcutsView.findViewById(R.id.shortcut_open_apps);
mButtonSpecificApp = keyboardShortcutsView.findViewById(R.id.shortcut_specific_app);
+ LinearLayout shortcutsContainer = keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container);
+
mButtonSystem.setOnClickListener(v -> {
setCurrentCategoryIndex(SHORTCUT_SYSTEM_INDEX);
- populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_container));
+ populateKeyboardShortcutSearchList(shortcutsContainer);
+ shortcutsContainer.setAccessibilityPaneTitle(mContext.getString(
+ R.string.keyboard_shortcut_a11y_filter_system));
});
mButtonInput.setOnClickListener(v -> {
setCurrentCategoryIndex(SHORTCUT_INPUT_INDEX);
- populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_container));
+ populateKeyboardShortcutSearchList(shortcutsContainer);
+ shortcutsContainer.setAccessibilityPaneTitle(mContext.getString(
+ R.string.keyboard_shortcut_a11y_filter_input));
});
mButtonOpenApps.setOnClickListener(v -> {
setCurrentCategoryIndex(SHORTCUT_OPENAPPS_INDEX);
- populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_container));
+ populateKeyboardShortcutSearchList(shortcutsContainer);
+ shortcutsContainer.setAccessibilityPaneTitle(mContext.getString(
+ R.string.keyboard_shortcut_a11y_filter_open_apps));
});
mButtonSpecificApp.setOnClickListener(v -> {
setCurrentCategoryIndex(SHORTCUT_SPECIFICAPP_INDEX);
- populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_container));
+ populateKeyboardShortcutSearchList(shortcutsContainer);
+ shortcutsContainer.setAccessibilityPaneTitle(mContext.getString(
+ R.string.keyboard_shortcut_a11y_filter_current_app));
});
mFullButtonList.add(mButtonSystem);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 61eaff9c2f8e..acb00d5016f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -85,7 +85,6 @@ public final class KeyboardShortcuts {
private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
private final SparseArray<String> mModifierNames = new SparseArray<>();
- private final SparseArray<Drawable> mSpecialCharacterDrawables = new SparseArray<>();
private final SparseArray<Drawable> mModifierDrawables = new SparseArray<>();
// Ordered list of modifiers that are supported. All values in this array must exist in
// mModifierNames.
@@ -340,19 +339,6 @@ public final class KeyboardShortcuts {
mModifierNames.put(KeyEvent.META_SYM_ON, "Sym");
mModifierNames.put(KeyEvent.META_FUNCTION_ON, "Fn");
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_DEL, context.getDrawable(R.drawable.ic_ksh_key_backspace));
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_ENTER, context.getDrawable(R.drawable.ic_ksh_key_enter));
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_DPAD_UP, context.getDrawable(R.drawable.ic_ksh_key_up));
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_DPAD_RIGHT, context.getDrawable(R.drawable.ic_ksh_key_right));
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_DPAD_DOWN, context.getDrawable(R.drawable.ic_ksh_key_down));
- mSpecialCharacterDrawables.put(
- KeyEvent.KEYCODE_DPAD_LEFT, context.getDrawable(R.drawable.ic_ksh_key_left));
-
mModifierDrawables.put(
KeyEvent.META_META_ON, context.getDrawable(R.drawable.ic_ksh_key_meta));
}
@@ -747,9 +733,6 @@ public final class KeyboardShortcuts {
Drawable shortcutKeyDrawable = null;
if (info.getBaseCharacter() > Character.MIN_VALUE) {
shortcutKeyString = String.valueOf(info.getBaseCharacter());
- } else if (mSpecialCharacterDrawables.get(info.getKeycode()) != null) {
- shortcutKeyDrawable = mSpecialCharacterDrawables.get(info.getKeycode());
- shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
} else if (mSpecialCharacterNames.get(info.getKeycode()) != null) {
shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
index 31893b402e3c..e90ddf98db00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
@@ -15,37 +15,48 @@
package com.android.systemui.statusbar.notification.domain.interactor
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.statusbar.notification.collection.render.NotifStats
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
class ActiveNotificationsInteractor
@Inject
constructor(
private val repository: ActiveNotificationListRepository,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
) {
/** Notifications actively presented to the user in the notification stack, in order. */
val topLevelRepresentativeNotifications: Flow<List<ActiveNotificationModel>> =
- repository.activeNotifications.map { store ->
- store.renderList.map { key ->
- val entry =
- store[key]
- ?: error("Could not find notification with key $key in active notif store.")
- when (entry) {
- is ActiveNotificationGroupModel -> entry.summary
- is ActiveNotificationModel -> entry
+ repository.activeNotifications
+ .map { store ->
+ store.renderList.map { key ->
+ val entry =
+ store[key]
+ ?: error(
+ "Could not find notification with key $key in active notif store."
+ )
+ when (entry) {
+ is ActiveNotificationGroupModel -> entry.summary
+ is ActiveNotificationModel -> entry
+ }
}
}
- }
+ .flowOn(backgroundDispatcher)
/** Are any notifications being actively presented in the notification stack? */
val areAnyNotificationsPresent: Flow<Boolean> =
- repository.activeNotifications.map { it.renderList.isNotEmpty() }.distinctUntilChanged()
+ repository.activeNotifications
+ .map { it.renderList.isNotEmpty() }
+ .distinctUntilChanged()
+ .flowOn(backgroundDispatcher)
/**
* The same as [areAnyNotificationsPresent], but without flows, for easy access in synchronous
@@ -59,6 +70,7 @@ constructor(
repository.notifStats
.map { it.hasClearableAlertingNotifs || it.hasClearableSilentNotifs }
.distinctUntilChanged()
+ .flowOn(backgroundDispatcher)
fun setNotifStats(notifStats: NotifStats) {
repository.notifStats.value = notifStats
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt
index 87b8e55dbd1a..73341dbc4999 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt
@@ -15,19 +15,24 @@
*/
package com.android.systemui.statusbar.notification.domain.interactor
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOn
/** Domain logic pertaining to notifications on the keyguard. */
class NotificationsKeyguardInteractor
@Inject
constructor(
repository: NotificationsKeyguardViewStateRepository,
+ @Background backgroundDispatcher: CoroutineDispatcher,
) {
/** Is a pulse expansion occurring? */
- val isPulseExpanding: Flow<Boolean> = repository.isPulseExpanding
+ val isPulseExpanding: Flow<Boolean> = repository.isPulseExpanding.flowOn(backgroundDispatcher)
/** Are notifications fully hidden from view? */
- val areNotificationsFullyHidden: Flow<Boolean> = repository.areNotificationsFullyHidden
+ val areNotificationsFullyHidden: Flow<Boolean> =
+ repository.areNotificationsFullyHidden.flowOn(backgroundDispatcher)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
index 0299114e0afc..e0eee96d8f0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
@@ -34,34 +34,38 @@ object FooterViewBinder {
viewModel: FooterViewModel,
clearAllNotifications: View.OnClickListener,
): DisposableHandle {
- // Listen for changes when the view is attached.
+ // Bind the resource IDs
+ footer.setMessageString(viewModel.message.messageId)
+ footer.setMessageIcon(viewModel.message.iconId)
+ footer.setClearAllButtonText(viewModel.clearAllButton.labelId)
+ footer.setClearAllButtonDescription(viewModel.clearAllButton.accessibilityDescriptionId)
+
+ // Bind the click listeners
+ footer.setClearAllButtonClickListener(clearAllNotifications)
+
+ // Listen for visibility changes when the view is attached.
return footer.repeatWhenAttached {
lifecycleScope.launch {
- viewModel.clearAllButton.collect { button ->
- if (button.isVisible.isAnimating) {
+ viewModel.clearAllButton.isVisible.collect { isVisible ->
+ if (isVisible.isAnimating) {
footer.setClearAllButtonVisible(
- button.isVisible.value,
+ isVisible.value,
/* animate = */ true,
) { _ ->
- button.isVisible.stopAnimating()
+ isVisible.stopAnimating()
}
} else {
footer.setClearAllButtonVisible(
- button.isVisible.value,
+ isVisible.value,
/* animate = */ false,
)
}
- footer.setClearAllButtonText(button.labelId)
- footer.setClearAllButtonDescription(button.accessibilityDescriptionId)
- footer.setClearAllButtonClickListener(clearAllNotifications)
}
}
lifecycleScope.launch {
- viewModel.message.collect { message ->
- footer.setFooterLabelVisible(message.visible)
- footer.setMessageString(message.messageId)
- footer.setMessageIcon(message.iconId)
+ viewModel.message.isVisible.collect { visible ->
+ footer.setFooterLabelVisible(visible)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterButtonViewModel.kt
index ea5abeff7042..244555a3d73b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterButtonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterButtonViewModel.kt
@@ -18,9 +18,10 @@ package com.android.systemui.statusbar.notification.footer.ui.viewmodel
import android.annotation.StringRes
import com.android.systemui.util.ui.AnimatedValue
+import kotlinx.coroutines.flow.Flow
data class FooterButtonViewModel(
@StringRes val labelId: Int,
@StringRes val accessibilityDescriptionId: Int,
- val isVisible: AnimatedValue<Boolean>,
+ val isVisible: Flow<AnimatedValue<Boolean>>,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt
index bc912fb106f0..85cd397a3749 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt
@@ -18,10 +18,11 @@ package com.android.systemui.statusbar.notification.footer.ui.viewmodel
import android.annotation.DrawableRes
import android.annotation.StringRes
+import kotlinx.coroutines.flow.StateFlow
/** A ViewModel for the string message that can be shown in the footer. */
data class FooterMessageViewModel(
@StringRes val messageId: Int,
@DrawableRes val iconId: Int,
- val visible: Boolean,
+ val isVisible: StateFlow<Boolean>,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
index 721bea1086e6..e6b0abcfad65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
@@ -30,9 +30,7 @@ import dagger.Module
import dagger.Provides
import java.util.Optional
import javax.inject.Provider
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
/** ViewModel for [FooterView]. */
@@ -41,36 +39,32 @@ class FooterViewModel(
seenNotificationsInteractor: SeenNotificationsInteractor,
shadeInteractor: ShadeInteractor,
) {
- val clearAllButton: Flow<FooterButtonViewModel> =
- activeNotificationsInteractor.hasClearableNotifications
- .sample(
- combine(
- shadeInteractor.isShadeFullyExpanded,
- shadeInteractor.isShadeTouchable,
- ::Pair
- )
- .onStart { emit(Pair(false, false)) }
- ) { hasClearableNotifications, (isShadeFullyExpanded, animationsEnabled) ->
- val shouldAnimate = isShadeFullyExpanded && animationsEnabled
- AnimatableEvent(hasClearableNotifications, shouldAnimate)
- }
- .toAnimatedValueFlow()
- .map { visible ->
- FooterButtonViewModel(
- labelId = R.string.clear_all_notifications_text,
- accessibilityDescriptionId = R.string.accessibility_clear_all,
- isVisible = visible,
- )
- }
+ val clearAllButton: FooterButtonViewModel =
+ FooterButtonViewModel(
+ labelId = R.string.clear_all_notifications_text,
+ accessibilityDescriptionId = R.string.accessibility_clear_all,
+ isVisible =
+ activeNotificationsInteractor.hasClearableNotifications
+ .sample(
+ combine(
+ shadeInteractor.isShadeFullyExpanded,
+ shadeInteractor.isShadeTouchable,
+ ::Pair
+ )
+ .onStart { emit(Pair(false, false)) }
+ ) { hasClearableNotifications, (isShadeFullyExpanded, animationsEnabled) ->
+ val shouldAnimate = isShadeFullyExpanded && animationsEnabled
+ AnimatableEvent(hasClearableNotifications, shouldAnimate)
+ }
+ .toAnimatedValueFlow(),
+ )
- val message: Flow<FooterMessageViewModel> =
- seenNotificationsInteractor.hasFilteredOutSeenNotifications.map { hasFilteredOutNotifs ->
- FooterMessageViewModel(
- messageId = R.string.unlock_to_see_notif_text,
- iconId = R.drawable.ic_friction_lock_closed,
- visible = hasFilteredOutNotifs,
- )
- }
+ val message: FooterMessageViewModel =
+ FooterMessageViewModel(
+ messageId = R.string.unlock_to_see_notif_text,
+ iconId = R.drawable.ic_friction_lock_closed,
+ isVisible = seenNotificationsInteractor.hasFilteredOutSeenNotifications,
+ )
}
@Module
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 6944453506a8..3bbdfd164ba7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1275,6 +1275,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
*/
private void updateChildren() {
+ Trace.beginSection("NSSL#updateChildren");
updateScrollStateForAddedChildren();
mAmbientState.setCurrentScrollVelocity(mScroller.isFinished()
? 0
@@ -1285,6 +1286,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
} else {
startAnimationToState();
}
+ Trace.endSection();
}
private void onPreDrawDuringAnimation() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 4554085c35c0..a4e1a9c502f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -24,10 +24,12 @@ import com.android.internal.logging.nano.MetricsProto
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.common.ui.reinflateAndBindLatest
import com.android.systemui.common.ui.view.setImportantForAccessibilityYesNo
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.statusbar.NotificationShelf
+import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
import com.android.systemui.statusbar.notification.footer.ui.viewbinder.FooterViewBinder
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.ShelfNotificationIconViewStore
@@ -40,6 +42,7 @@ import com.android.systemui.statusbar.notification.stack.ui.viewmodel.Notificati
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.policy.ConfigurationController
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -48,12 +51,13 @@ class NotificationListViewBinder
@Inject
constructor(
private val viewModel: NotificationListViewModel,
- private val metricsLogger: MetricsLogger,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
private val configuration: ConfigurationState,
private val configurationController: ConfigurationController,
private val falsingManager: FalsingManager,
private val iconAreaController: NotificationIconAreaController,
private val iconViewBindingFailureTracker: StatusBarIconViewBindingFailureTracker,
+ private val metricsLogger: MetricsLogger,
private val shelfIconViewStore: ShelfNotificationIconViewStore,
) {
@@ -62,14 +66,17 @@ constructor(
viewController: NotificationStackScrollLayoutController
) {
bindShelf(view)
- bindFooter(view)
- bindEmptyShade(view)
bindHideList(viewController, viewModel)
- view.repeatWhenAttached {
- lifecycleScope.launch {
- viewModel.isImportantForAccessibility.collect { isImportantForAccessibility ->
- view.setImportantForAccessibilityYesNo(isImportantForAccessibility)
+ if (FooterViewRefactor.isEnabled) {
+ bindFooter(view)
+ bindEmptyShade(view)
+
+ view.repeatWhenAttached {
+ lifecycleScope.launch {
+ viewModel.isImportantForAccessibility.collect { isImportantForAccessibility ->
+ view.setImportantForAccessibilityYesNo(isImportantForAccessibility)
+ }
}
}
}
@@ -101,6 +108,7 @@ constructor(
R.layout.status_bar_notification_footer,
parentView,
attachToRoot = false,
+ backgroundDispatcher,
) { footerView: FooterView ->
traceSection("bind FooterView") {
val disposableHandle =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 674f1698d2a3..a3d316b611a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -22,6 +22,7 @@ import android.content.pm.PackageManager
import android.hardware.biometrics.BiometricSourceType
import android.provider.Settings
import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.ListenersTracing.forEachTraced
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -186,7 +187,9 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
}
}
- private fun notifyListeners() = listeners.forEach { it.onBypassStateChanged(bypassEnabled) }
+ private fun notifyListeners() = listeners.forEachTraced("KeyguardBypassController") {
+ it.onBypassStateChanged(bypassEnabled)
+ }
/**
* Notify that the biometric unlock has happened.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
index a32a5ab13748..8f1ac812da71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
@@ -22,11 +22,14 @@ import android.util.SparseIntArray;
import androidx.annotation.NonNull;
+import com.android.app.tracing.ListenersTracing;
import com.android.internal.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.Assert;
+import kotlin.Unit;
+
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -75,7 +78,11 @@ public class DevicePostureControllerImpl implements DevicePostureController {
mCurrentDevicePosture =
mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
- mListeners.forEach(l -> l.onPostureChanged(mCurrentDevicePosture));
+ ListenersTracing.INSTANCE.forEachTraced(mListeners, "DevicePostureControllerImpl",
+ l -> {
+ l.onPostureChanged(mCurrentDevicePosture);
+ return Unit.INSTANCE;
+ });
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
index e4e9554e1ab7..b59878253aa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
@@ -125,14 +125,19 @@ public class StatusBarWindowController {
* is different.
*/
public void refreshStatusBarHeight() {
- int heightFromConfig = SystemBarUtils.getStatusBarHeight(mContext);
+ Trace.beginSection("StatusBarWindowController#refreshStatusBarHeight");
+ try {
+ int heightFromConfig = SystemBarUtils.getStatusBarHeight(mContext);
- if (mBarHeight != heightFromConfig) {
- mBarHeight = heightFromConfig;
- apply(mCurrentState);
- }
+ if (mBarHeight != heightFromConfig) {
+ mBarHeight = heightFromConfig;
+ apply(mCurrentState);
+ }
- if (DEBUG) Log.v(TAG, "defineSlots");
+ if (DEBUG) Log.v(TAG, "defineSlots");
+ } finally {
+ Trace.endSection();
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 5a9f5d5a72d2..886fa70d715d 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -19,6 +19,7 @@ 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.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;
@@ -71,12 +72,15 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.monet.ColorScheme;
import com.android.systemui.monet.Style;
import com.android.systemui.monet.TonalPalette;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.SecureSettings;
import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors;
@@ -127,7 +131,6 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
private final SecureSettings mSecureSettings;
private final Executor mMainExecutor;
private final Handler mBgHandler;
- private final boolean mIsMonochromaticEnabled;
private final Context mContext;
private final boolean mIsMonetEnabled;
private final boolean mIsFidelityEnabled;
@@ -161,6 +164,8 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
private final SparseArray<WallpaperColors> mDeferredWallpaperColors = new SparseArray<>();
private final SparseIntArray mDeferredWallpaperColorsFlags = new SparseIntArray();
private final WakefulnessLifecycle mWakefulnessLifecycle;
+ private final JavaAdapter mJavaAdapter;
+ private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private final UiModeManager mUiModeManager;
private DynamicScheme mDynamicSchemeDark;
private DynamicScheme mDynamicSchemeLight;
@@ -200,8 +205,12 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
return;
}
boolean currentUser = userId == mUserTracker.getUserId();
- if (currentUser && !mAcceptColorEvents
- && mWakefulnessLifecycle.getWakefulness() != WAKEFULNESS_ASLEEP) {
+ boolean isAsleep = themeOverlayControllerWakefulnessDeprecation()
+ ? mKeyguardTransitionInteractor.isFinishedInStateWhereValue(
+ state -> KeyguardState.Companion.deviceIsAsleepInState(state))
+ : mWakefulnessLifecycle.getWakefulness() != WAKEFULNESS_ASLEEP;
+
+ if (currentUser && !mAcceptColorEvents && isAsleep) {
mDeferredWallpaperColors.put(userId, wallpaperColors);
mDeferredWallpaperColorsFlags.put(userId, which);
Log.i(TAG, "colors received; processing deferred until screen off: "
@@ -395,9 +404,10 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
FeatureFlags featureFlags,
@Main Resources resources,
WakefulnessLifecycle wakefulnessLifecycle,
+ JavaAdapter javaAdapter,
+ KeyguardTransitionInteractor keyguardTransitionInteractor,
UiModeManager uiModeManager) {
mContext = context;
- mIsMonochromaticEnabled = featureFlags.isEnabled(Flags.MONOCHROMATIC_THEME);
mIsMonetEnabled = featureFlags.isEnabled(Flags.MONET);
mIsFidelityEnabled = featureFlags.isEnabled(Flags.COLOR_FIDELITY);
mDeviceProvisionedController = deviceProvisionedController;
@@ -412,6 +422,8 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
mUserTracker = userTracker;
mResources = resources;
mWakefulnessLifecycle = wakefulnessLifecycle;
+ mJavaAdapter = javaAdapter;
+ mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mUiModeManager = uiModeManager;
dumpManager.registerDumpable(TAG, this);
}
@@ -494,21 +506,34 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
}
mWallpaperManager.addOnColorsChangedListener(mOnColorsChangedListener, null,
UserHandle.USER_ALL);
- mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
- @Override
- public void onFinishedGoingToSleep() {
- final int userId = mUserTracker.getUserId();
- final WallpaperColors colors = mDeferredWallpaperColors.get(userId);
- if (colors != null) {
- int flags = mDeferredWallpaperColorsFlags.get(userId);
-
- mDeferredWallpaperColors.put(userId, null);
- mDeferredWallpaperColorsFlags.put(userId, 0);
-
- handleWallpaperColors(colors, flags, userId);
- }
+
+ Runnable whenAsleepHandler = () -> {
+ final int userId = mUserTracker.getUserId();
+ final WallpaperColors colors = mDeferredWallpaperColors.get(userId);
+ if (colors != null) {
+ int flags = mDeferredWallpaperColorsFlags.get(userId);
+
+ mDeferredWallpaperColors.put(userId, null);
+ mDeferredWallpaperColorsFlags.put(userId, 0);
+
+ handleWallpaperColors(colors, flags, userId);
}
- });
+ };
+
+ if (themeOverlayControllerWakefulnessDeprecation()) {
+ mJavaAdapter.alwaysCollectFlow(
+ mKeyguardTransitionInteractor.isFinishedInState(KeyguardState.DOZING),
+ isFinishedInDozing -> {
+ if (isFinishedInDozing) whenAsleepHandler.run();
+ });
+ } else {
+ mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
+ @Override
+ public void onFinishedGoingToSleep() {
+ whenAsleepHandler.run();
+ }
+ });
+ }
}
private void reevaluateSystemTheme(boolean forceReload) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapper.kt
index a2a44e46919f..b2297d0d5821 100644
--- a/packages/SystemUI/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapper.kt
@@ -30,14 +30,16 @@ class LoopedAnimatable2DrawableWrapper private constructor(private val animatabl
private val loopedCallback = LoopedCallback()
+ private var isLoopedCallbackRegistered: Boolean = false
+
override fun start() {
animatable2.start()
- animatable2.registerAnimationCallback(loopedCallback)
+ setLoopingRegistered(true)
}
override fun stop() {
// stop looping if someone stops the animation
- animatable2.unregisterAnimationCallback(loopedCallback)
+ setLoopingRegistered(false)
animatable2.stop()
}
@@ -49,7 +51,25 @@ class LoopedAnimatable2DrawableWrapper private constructor(private val animatabl
override fun unregisterAnimationCallback(callback: Animatable2.AnimationCallback): Boolean =
animatable2.unregisterAnimationCallback(callback)
- override fun clearAnimationCallbacks() = animatable2.clearAnimationCallbacks()
+ override fun clearAnimationCallbacks() {
+ animatable2.clearAnimationCallbacks()
+ // re-register looped callback to maintain looped behaviour. LoopedCallback is a static
+ // class and it has no extra references, so it doesn't provoke a memory leak.
+ isLoopedCallbackRegistered = false
+ setLoopingRegistered(true)
+ }
+
+ private fun setLoopingRegistered(isLooping: Boolean) {
+ if (isLooping == isLoopedCallbackRegistered) {
+ return
+ }
+ isLoopedCallbackRegistered = isLooping
+ if (isLooping) {
+ animatable2.registerAnimationCallback(loopedCallback)
+ } else {
+ animatable2.unregisterAnimationCallback(loopedCallback)
+ }
+ }
override fun getConstantState(): ConstantState? =
drawable!!.constantState?.let(LoopedAnimatable2DrawableWrapper::LoopedDrawableState)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt
index c825d2ea65ad..834179bf289d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt
@@ -38,6 +38,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -97,7 +98,8 @@ class DisplayStateRepositoryTest : SysuiTestCase() {
deviceStateManager,
displayManager,
handler,
- fakeExecutor
+ fakeExecutor,
+ UnconfinedTestDispatcher(),
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/ConfigurationStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/common/ui/ConfigurationStateTest.kt
index 034b8022305a..112cec25784c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/common/ui/ConfigurationStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/ConfigurationStateTest.kt
@@ -30,6 +30,8 @@ import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -44,102 +46,112 @@ class ConfigurationStateTest : SysuiTestCase() {
private val configurationController: ConfigurationController = mock()
private val layoutInflater = TestLayoutInflater()
+ private val backgroundDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(backgroundDispatcher)
val underTest = ConfigurationState(configurationController, context, layoutInflater)
@Test
- fun reinflateAndBindLatest_inflatesWithoutEmission() = runTest {
- var callbackCount = 0
- backgroundScope.launch {
- underTest.reinflateAndBindLatest<View>(
- resource = 0,
- root = null,
- attachToRoot = false,
- ) {
- callbackCount++
- null
+ fun reinflateAndBindLatest_inflatesWithoutEmission() =
+ testScope.runTest {
+ var callbackCount = 0
+ backgroundScope.launch {
+ underTest.reinflateAndBindLatest<View>(
+ resource = 0,
+ root = null,
+ attachToRoot = false,
+ backgroundDispatcher,
+ ) {
+ callbackCount++
+ null
+ }
}
- }
- // Inflates without an emission
- runCurrent()
- assertThat(layoutInflater.inflationCount).isEqualTo(1)
- assertThat(callbackCount).isEqualTo(1)
- }
+ // Inflates without an emission
+ runCurrent()
+ assertThat(layoutInflater.inflationCount).isEqualTo(1)
+ assertThat(callbackCount).isEqualTo(1)
+ }
@Test
- fun reinflateAndBindLatest_reinflatesOnThemeChanged() = runTest {
- var callbackCount = 0
- backgroundScope.launch {
- underTest.reinflateAndBindLatest<View>(
- resource = 0,
- root = null,
- attachToRoot = false,
- ) {
- callbackCount++
- null
+ fun reinflateAndBindLatest_reinflatesOnThemeChanged() =
+ testScope.runTest {
+ var callbackCount = 0
+ backgroundScope.launch {
+ underTest.reinflateAndBindLatest<View>(
+ resource = 0,
+ root = null,
+ attachToRoot = false,
+ backgroundDispatcher,
+ ) {
+ callbackCount++
+ null
+ }
}
- }
- runCurrent()
+ runCurrent()
- val configListeners: List<ConfigurationController.ConfigurationListener> = captureMany {
- verify(configurationController, atLeastOnce()).addCallback(capture())
- }
+ val configListeners: List<ConfigurationController.ConfigurationListener> = captureMany {
+ verify(configurationController, atLeastOnce()).addCallback(capture())
+ }
- listOf(1, 2, 3).forEach { count ->
- assertThat(layoutInflater.inflationCount).isEqualTo(count)
- assertThat(callbackCount).isEqualTo(count)
- configListeners.forEach { it.onThemeChanged() }
- runCurrent()
+ listOf(1, 2, 3).forEach { count ->
+ assertThat(layoutInflater.inflationCount).isEqualTo(count)
+ assertThat(callbackCount).isEqualTo(count)
+ configListeners.forEach { it.onThemeChanged() }
+ runCurrent()
+ }
}
- }
@Test
- fun reinflateAndBindLatest_reinflatesOnDensityOrFontScaleChanged() = runTest {
- var callbackCount = 0
- backgroundScope.launch {
- underTest.reinflateAndBindLatest<View>(
- resource = 0,
- root = null,
- attachToRoot = false,
- ) {
- callbackCount++
- null
+ fun reinflateAndBindLatest_reinflatesOnDensityOrFontScaleChanged() =
+ testScope.runTest {
+ var callbackCount = 0
+ backgroundScope.launch {
+ underTest.reinflateAndBindLatest<View>(
+ resource = 0,
+ root = null,
+ attachToRoot = false,
+ backgroundDispatcher,
+ ) {
+ callbackCount++
+ null
+ }
}
- }
- runCurrent()
+ runCurrent()
- val configListeners: List<ConfigurationController.ConfigurationListener> = captureMany {
- verify(configurationController, atLeastOnce()).addCallback(capture())
- }
+ val configListeners: List<ConfigurationController.ConfigurationListener> = captureMany {
+ verify(configurationController, atLeastOnce()).addCallback(capture())
+ }
- listOf(1, 2, 3).forEach { count ->
- assertThat(layoutInflater.inflationCount).isEqualTo(count)
- assertThat(callbackCount).isEqualTo(count)
- configListeners.forEach { it.onDensityOrFontScaleChanged() }
- runCurrent()
+ listOf(1, 2, 3).forEach { count ->
+ assertThat(layoutInflater.inflationCount).isEqualTo(count)
+ assertThat(callbackCount).isEqualTo(count)
+ configListeners.forEach { it.onDensityOrFontScaleChanged() }
+ runCurrent()
+ }
}
- }
@Test
- fun testReinflateAndBindLatest_disposesOnCancel() = runTest {
- var callbackCount = 0
- var disposed = false
- val job = launch {
- underTest.reinflateAndBindLatest<View>(
- resource = 0,
- root = null,
- attachToRoot = false,
- ) {
- callbackCount++
- DisposableHandle { disposed = true }
+ fun testReinflateAndBindLatest_disposesOnCancel() =
+ testScope.runTest {
+ var callbackCount = 0
+ var disposed = false
+ val job = launch {
+ underTest.reinflateAndBindLatest<View>(
+ resource = 0,
+ root = null,
+ attachToRoot = false,
+ backgroundDispatcher,
+ ) {
+ callbackCount++
+ DisposableHandle { disposed = true }
+ }
}
- }
- runCurrent()
- job.cancelAndJoin()
- assertThat(disposed).isTrue()
- }
+ runCurrent()
+ job.cancelAndJoin()
+ assertThat(disposed).isTrue()
+ }
inner class TestLayoutInflater : LayoutInflater(context) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
index a58bc52bf8e5..2b7221ec192c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
@@ -34,6 +34,7 @@ import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -69,6 +70,7 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
authController,
keyguardUpdateMonitor,
testScope.backgroundScope,
+ UnconfinedTestDispatcher(),
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt
index 9be5558f5cc2..ae6c5b7b36b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -49,7 +50,11 @@ class DevicePostureRepositoryTest : SysuiTestCase() {
fun setup() {
MockitoAnnotations.initMocks(this)
testScope = TestScope()
- underTest = DevicePostureRepositoryImpl(postureController = devicePostureController)
+ underTest =
+ DevicePostureRepositoryImpl(
+ postureController = devicePostureController,
+ UnconfinedTestDispatcher()
+ )
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 9dfb5a5dcb3d..e082ca81ba4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -47,13 +47,13 @@ import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -305,7 +305,11 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
MediaOutputBaseDialogImpl(Context context, BroadcastSender broadcastSender,
MediaOutputController mediaOutputController) {
- super(context, broadcastSender, mediaOutputController);
+ super(
+ context,
+ broadcastSender,
+ mediaOutputController, /* includePlaybackAndAppMetadata */
+ true);
mAdapter = mMediaOutputBaseAdapter;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index 379136b0586f..d5dc502b1e6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -49,13 +49,13 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -394,8 +394,14 @@ public class MediaOutputDialogTest extends SysuiTestCase {
@NonNull
private MediaOutputDialog makeTestDialog(MediaOutputController controller) {
- return new MediaOutputDialog(mContext, false, mBroadcastSender,
- controller, mDialogLaunchAnimator, mUiEventLogger);
+ return new MediaOutputDialog(
+ mContext,
+ false,
+ mBroadcastSender,
+ controller,
+ mDialogLaunchAnimator,
+ mUiEventLogger,
+ true);
}
private void withTestDialog(MediaOutputController controller, Consumer<MediaOutputDialog> c) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index cf43b2e12283..b7618d290f53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -45,7 +45,6 @@ import android.provider.Settings
import androidx.test.ext.truth.content.IntentSubject.assertThat
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.notetask.NoteTaskController.Companion.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE
import com.android.systemui.notetask.NoteTaskController.Companion.SHORTCUT_ID
@@ -56,6 +55,7 @@ import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON
import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
+import com.android.systemui.res.R
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
@@ -162,6 +162,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
noteTaskBubblesController =
FakeNoteTaskBubbleController(context, testDispatcher, Optional.ofNullable(bubbles)),
applicationScope = testScope,
+ bgCoroutineContext = testScope.backgroundScope.coroutineContext
)
// region onBubbleExpandChanged
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 1dbb2972c6f3..62c0ebeb8c07 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,8 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
+
import android.content.res.Resources;
import android.os.Handler;
import android.os.Looper;
@@ -293,8 +295,10 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
)
);
- mActiveNotificationsInteractor =
- new ActiveNotificationsInteractor(new ActiveNotificationListRepository());
+ mActiveNotificationsInteractor = new ActiveNotificationsInteractor(
+ new ActiveNotificationListRepository(),
+ StandardTestDispatcher(/* scheduler = */ null, /* name = */ null)
+ );
KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
keyguardStatusView.setId(R.id.keyguard_status_view);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
index b86f8410fb7f..6374d5e259fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
@@ -25,14 +25,19 @@ import com.android.systemui.statusbar.notification.shared.byKey
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
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
@SmallTest
class RenderNotificationsListInteractorTest : SysuiTestCase() {
+ private val backgroundDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(backgroundDispatcher)
private val notifsRepository = ActiveNotificationListRepository()
- private val notifsInteractor = ActiveNotificationsInteractor(notifsRepository)
+ private val notifsInteractor =
+ ActiveNotificationsInteractor(notifsRepository, backgroundDispatcher)
private val underTest =
RenderNotificationListInteractor(
notifsRepository,
@@ -40,21 +45,26 @@ class RenderNotificationsListInteractorTest : SysuiTestCase() {
)
@Test
- fun setRenderedList_preservesOrdering() = runTest {
- val notifs by collectLastValue(notifsInteractor.topLevelRepresentativeNotifications)
- val keys = (1..50).shuffled().map { "$it" }
- val entries =
- keys.map {
- mock<ListEntry> {
- val mockRep = mock<NotificationEntry> {
- whenever(key).thenReturn(it)
- whenever(sbn).thenReturn(mock())
- whenever(icons).thenReturn(mock())
+ fun setRenderedList_preservesOrdering() =
+ testScope.runTest {
+ val notifs by collectLastValue(notifsInteractor.topLevelRepresentativeNotifications)
+ val keys = (1..50).shuffled().map { "$it" }
+ val entries =
+ keys.map {
+ mock<ListEntry> {
+ val mockRep =
+ mock<NotificationEntry> {
+ whenever(key).thenReturn(it)
+ whenever(sbn).thenReturn(mock())
+ whenever(icons).thenReturn(mock())
+ }
+ whenever(representativeEntry).thenReturn(mockRep)
}
- whenever(representativeEntry).thenReturn(mockRep)
}
- }
- underTest.setRenderedList(entries)
- assertThat(notifs).comparingElementsUsing(byKey).containsExactlyElementsIn(keys).inOrder()
- }
+ underTest.setRenderedList(entries)
+ assertThat(notifs)
+ .comparingElementsUsing(byKey)
+ .containsExactlyElementsIn(keys)
+ .inOrder()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
index 94dcf7a18514..0ba820f0972a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
@@ -116,27 +116,27 @@ class FooterViewModelTest : SysuiTestCase() {
@Test
fun testMessageVisible_whenFilteredNotifications() =
testComponent.runTest {
- val message by collectLastValue(footerViewModel.message)
+ val visible by collectLastValue(footerViewModel.message.isVisible)
activeNotificationListRepository.hasFilteredOutSeenNotifications.value = true
- assertThat(message?.visible).isTrue()
+ assertThat(visible).isTrue()
}
@Test
fun testMessageVisible_whenNoFilteredNotifications() =
testComponent.runTest {
- val message by collectLastValue(footerViewModel.message)
+ val visible by collectLastValue(footerViewModel.message.isVisible)
activeNotificationListRepository.hasFilteredOutSeenNotifications.value = false
- assertThat(message?.visible).isFalse()
+ assertThat(visible).isFalse()
}
@Test
fun testClearAllButtonVisible_whenHasClearableNotifs() =
testComponent.runTest {
- val button by collectLastValue(footerViewModel.clearAllButton)
+ val visible by collectLastValue(footerViewModel.clearAllButton.isVisible)
activeNotificationListRepository.notifStats.value =
NotifStats(
@@ -148,13 +148,13 @@ class FooterViewModelTest : SysuiTestCase() {
)
runCurrent()
- assertThat(button?.isVisible?.value).isTrue()
+ assertThat(visible?.value).isTrue()
}
@Test
fun testClearAllButtonVisible_whenHasNoClearableNotifs() =
testComponent.runTest {
- val button by collectLastValue(footerViewModel.clearAllButton)
+ val visible by collectLastValue(footerViewModel.clearAllButton.isVisible)
activeNotificationListRepository.notifStats.value =
NotifStats(
@@ -166,13 +166,13 @@ class FooterViewModelTest : SysuiTestCase() {
)
runCurrent()
- assertThat(button?.isVisible?.value).isFalse()
+ assertThat(visible?.value).isFalse()
}
@Test
fun testClearAllButtonAnimating_whenShadeExpandedAndTouchable() =
testComponent.runTest {
- val button by collectLastValue(footerViewModel.clearAllButton)
+ val visible by collectLastValue(footerViewModel.clearAllButton.isVisible)
runCurrent()
// WHEN shade is expanded
@@ -200,13 +200,13 @@ class FooterViewModelTest : SysuiTestCase() {
runCurrent()
// THEN button visibility should animate
- assertThat(button?.isVisible?.isAnimating).isTrue()
+ assertThat(visible?.isAnimating).isTrue()
}
@Test
fun testClearAllButtonAnimating_whenShadeNotExpanded() =
testComponent.runTest {
- val button by collectLastValue(footerViewModel.clearAllButton)
+ val visible by collectLastValue(footerViewModel.clearAllButton.isVisible)
runCurrent()
// WHEN shade is collapsed
@@ -234,6 +234,6 @@ class FooterViewModelTest : SysuiTestCase() {
runCurrent()
// THEN button visibility should not animate
- assertThat(button?.isVisible?.isAnimating).isFalse()
+ assertThat(visible?.isAnimating).isFalse()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index ff5c02622e4e..755897442eb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
import android.metrics.LogMaker;
import android.testing.AndroidTestingRunner;
@@ -169,7 +170,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
new ActiveNotificationListRepository();
private final ActiveNotificationsInteractor mActiveNotificationsInteractor =
- new ActiveNotificationsInteractor(mActiveNotificationsRepository);
+ new ActiveNotificationsInteractor(mActiveNotificationsRepository,
+ StandardTestDispatcher(/* scheduler = */ null, /* name = */ null));
private final SeenNotificationsInteractor mSeenNotificationsInteractor =
new SeenNotificationsInteractor(mActiveNotificationsRepository);
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 c454b45a7312..112368895888 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -61,10 +61,12 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.monet.Style;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.SecureSettings;
import com.google.common.util.concurrent.MoreExecutors;
@@ -88,7 +90,10 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
private static final int USER_SYSTEM = UserHandle.USER_SYSTEM;
private static final int USER_SECONDARY = 10;
-
+ @Mock
+ private JavaAdapter mJavaAdapter;
+ @Mock
+ private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private ThemeOverlayController mThemeOverlayController;
@Mock
private Executor mBgExecutor;
@@ -150,11 +155,12 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
.thenReturn(Color.YELLOW);
when(mResources.getColor(eq(android.R.color.system_neutral2_500), any()))
.thenReturn(Color.BLACK);
+
mThemeOverlayController = new ThemeOverlayController(mContext,
mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
- mUiModeManager) {
+ mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager) {
@VisibleForTesting
protected boolean isNightMode() {
return false;
@@ -736,7 +742,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
- mUiModeManager) {
+ mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager) {
@VisibleForTesting
protected boolean isNightMode() {
return false;
@@ -776,7 +782,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
- mUiModeManager) {
+ mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager) {
@VisibleForTesting
protected boolean isNightMode() {
return false;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapperTest.kt
index 6d2f00d50d78..080689a5ca8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapperTest.kt
@@ -59,13 +59,36 @@ class LoopedAnimatable2DrawableWrapperTest : SysuiTestCase() {
}
@Test
+ fun multipleStartAddsTheCallbackOnce() {
+ underTest.start()
+ underTest.start()
+ underTest.start()
+ underTest.start()
+
+ verify(drawable).registerAnimationCallback(any())
+ }
+
+ @Test
fun stopRemovesTheCallback() {
+ underTest.start()
+
underTest.stop()
verify(drawable).unregisterAnimationCallback(any())
}
@Test
+ fun callbackSurvivesClearAnimationCallbacks() {
+ underTest.start()
+
+ underTest.clearAnimationCallbacks()
+
+ verify(drawable).clearAnimationCallbacks()
+ // start + re-add after #clearAnimationCallbacks
+ verify(drawable, times(2)).registerAnimationCallback(capture(callbackCaptor))
+ }
+
+ @Test
fun animationLooped() {
underTest.start()
verify(drawable).registerAnimationCallback(capture(callbackCaptor))
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 8aa729cedde2..52c25f7b2b71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -522,7 +522,8 @@ public class BubblesTest extends SysuiTestCase {
(sysUiFlags & QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED) != 0;
});
- mPositioner = new TestableBubblePositioner(mContext, mWindowManager);
+ mPositioner = new TestableBubblePositioner(mContext,
+ mContext.getSystemService(WindowManager.class));
mPositioner.setMaxBubbles(5);
mBubbleData = new BubbleData(mContext, mBubbleLogger, mPositioner, mEducationController,
syncExecutor);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorKosmos.kt
index 3d7fb6d91393..01f453570e63 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorKosmos.kt
@@ -17,7 +17,10 @@
package com.android.systemui.statusbar.notification.domain.interactor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
val Kosmos.activeNotificationsInteractor by
- Kosmos.Fixture { ActiveNotificationsInteractor(activeNotificationListRepository) }
+ Kosmos.Fixture {
+ ActiveNotificationsInteractor(activeNotificationListRepository, testDispatcher)
+ }
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 3f46ab859bf9..e013a3e41896 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -34,6 +34,7 @@ java_library {
"framework-minus-apex.ravenwood",
"junit",
],
+ sdk_version: "core_current",
visibility: ["//frameworks/base"],
}
diff --git a/services/Android.bp b/services/Android.bp
index 02a7a78653aa..5cb8ec628c38 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -140,6 +140,7 @@ filegroup {
":services.voiceinteraction-sources",
":services.wallpapereffectsgeneration-sources",
":services.wifi-sources",
+ ":framework-pm-common-shared-srcs",
],
visibility: ["//visibility:private"],
}
diff --git a/services/companion/java/com/android/server/companion/virtual/OWNERS b/services/companion/java/com/android/server/companion/virtual/OWNERS
index 5295ec82e3c3..4fe0592f9075 100644
--- a/services/companion/java/com/android/server/companion/virtual/OWNERS
+++ b/services/companion/java/com/android/server/companion/virtual/OWNERS
@@ -2,7 +2,7 @@
set noparent
-ogunwale@google.com
-michaelwr@google.com
+marvinramin@google.com
vladokom@google.com
-marvinramin@google.com \ No newline at end of file
+ogunwale@google.com
+michaelwr@google.com \ No newline at end of file
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 e51ef297519f..d194bb29b19b 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -187,9 +187,7 @@ public class VirtualDeviceManagerService extends SystemService {
CompanionDeviceManager cdm =
getContext().getSystemService(CompanionDeviceManager.class);
if (cdm != null) {
- synchronized (mVirtualDeviceManagerLock) {
- mActiveAssociations = cdm.getAllAssociations(UserHandle.USER_ALL);
- }
+ onCdmAssociationsChanged(cdm.getAllAssociations(UserHandle.USER_ALL));
cdm.addOnAssociationsChangedListener(getContext().getMainExecutor(),
this::onCdmAssociationsChanged, UserHandle.USER_ALL);
} else {
@@ -345,19 +343,21 @@ public class VirtualDeviceManagerService extends SystemService {
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
void onCdmAssociationsChanged(List<AssociationInfo> associations) {
+ List<AssociationInfo> vdmAssociations = new ArrayList<>();
+ Set<Integer> activeAssociationIds = new HashSet<>();
+ for (int i = 0; i < associations.size(); ++i) {
+ AssociationInfo association = associations.get(i);
+ if (VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES.contains(association.getDeviceProfile())) {
+ vdmAssociations.add(association);
+ activeAssociationIds.add(association.getId());
+ }
+ }
Set<VirtualDeviceImpl> virtualDevicesToRemove = new HashSet<>();
Set<String> removedPersistentDeviceIds = new HashSet<>();
synchronized (mVirtualDeviceManagerLock) {
- Set<Integer> activeAssociationIds = new HashSet<>(associations.size());
- for (int i = 0; i < associations.size(); ++i) {
- activeAssociationIds.add(associations.get(i).getId());
- }
-
for (int i = 0; i < mActiveAssociations.size(); ++i) {
AssociationInfo associationInfo = mActiveAssociations.get(i);
- if (!activeAssociationIds.contains(associationInfo.getId())
- && VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES.contains(
- associationInfo.getDeviceProfile())) {
+ if (!activeAssociationIds.contains(associationInfo.getId())) {
removedPersistentDeviceIds.add(
VirtualDeviceImpl.createPersistentDeviceId(associationInfo.getId()));
}
@@ -370,7 +370,7 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
- mActiveAssociations = associations;
+ mActiveAssociations = vdmAssociations;
}
for (VirtualDeviceImpl virtualDevice : virtualDevicesToRemove) {
@@ -869,12 +869,8 @@ public class VirtualDeviceManagerService extends SystemService {
synchronized (mVirtualDeviceManagerLock) {
for (int i = 0; i < mActiveAssociations.size(); ++i) {
AssociationInfo associationInfo = mActiveAssociations.get(i);
- if (VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES.contains(
- associationInfo.getDeviceProfile())) {
- persistentIds.add(
- VirtualDeviceImpl.createPersistentDeviceId(
- associationInfo.getId()));
- }
+ persistentIds.add(
+ VirtualDeviceImpl.createPersistentDeviceId(associationInfo.getId()));
}
}
return persistentIds;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c64fb2366dd6..54c8ed38bb1c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4852,8 +4852,10 @@ public class ActivityManagerService extends IActivityManager.Stub
} else {
Slog.wtf(TAG, "Mismatched or missing ProcessRecord: " + app + ". Pid: " + pid
+ ". Uid: " + uid);
- killProcess(pid);
- killProcessGroup(uid, pid);
+ if (pid > 0) {
+ killProcess(pid);
+ killProcessGroup(uid, pid);
+ }
mProcessList.noteAppKill(pid, uid,
ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
ApplicationExitInfo.SUBREASON_UNKNOWN,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9701fc87b2a6..d4b72c1770f7 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -18,6 +18,8 @@ package com.android.server.audio;
import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED;
import static android.app.BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT;
+import static android.media.audio.Flags.autoPublicVolumeApiHardening;
+import static android.media.audio.Flags.focusFreezeTestApi;
import static android.media.AudioDeviceInfo.TYPE_BLE_HEADSET;
import static android.media.AudioDeviceInfo.TYPE_BLE_SPEAKER;
import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
@@ -157,6 +159,7 @@ import android.media.permission.SafeCloseable;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
import android.media.projection.IMediaProjectionManager;
+import android.media.session.MediaSessionManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -314,6 +317,9 @@ public class AudioService extends IAudioService.Stub
private final ContentResolver mContentResolver;
private final AppOpsManager mAppOps;
+ /** do not use directly, use getMediaSessionManager() which handles lazy initialization */
+ @Nullable private volatile MediaSessionManager mMediaSessionManager;
+
// the platform type affects volume and silent mode behavior
private final int mPlatformType;
@@ -946,6 +952,8 @@ public class AudioService extends IAudioService.Stub
private final LoudnessCodecHelper mLoudnessCodecHelper;
+ private final HardeningEnforcer mHardeningEnforcer;
+
private final Object mSupportedSystemUsagesLock = new Object();
@GuardedBy("mSupportedSystemUsagesLock")
private @AttributeSystemUsage int[] mSupportedSystemUsages =
@@ -1322,6 +1330,8 @@ public class AudioService extends IAudioService.Stub
mDisplayManager = context.getSystemService(DisplayManager.class);
mMusicFxHelper = new MusicFxHelper(mContext, mAudioHandler);
+
+ mHardeningEnforcer = new HardeningEnforcer(mContext, isPlatformAutomotive());
}
private void initVolumeStreamStates() {
@@ -1393,7 +1403,6 @@ public class AudioService extends IAudioService.Stub
// check on volume initialization
checkVolumeRangeInitialization("AudioService()");
-
}
private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener =
@@ -1406,6 +1415,14 @@ public class AudioService extends IAudioService.Stub
}
};
+ private MediaSessionManager getMediaSessionManager() {
+ if (mMediaSessionManager == null) {
+ mMediaSessionManager = (MediaSessionManager) mContext
+ .getSystemService(Context.MEDIA_SESSION_SERVICE);
+ }
+ return mMediaSessionManager;
+ }
+
/**
* Initialize intent receives and settings observers for this service.
* Must be called after createStreamStates() as the handling of some events
@@ -3434,6 +3451,10 @@ public class AudioService extends IAudioService.Stub
* Part of service interface, check permissions here */
public void adjustStreamVolumeWithAttribution(int streamType, int direction, int flags,
String callingPackage, String attributionTag) {
+ if (mHardeningEnforcer.blockVolumeMethod(
+ HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_STREAM_VOLUME)) {
+ return;
+ }
if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Log.w(TAG, "Trying to call adjustStreamVolume() for a11y without"
+ "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage);
@@ -4214,6 +4235,10 @@ public class AudioService extends IAudioService.Stub
* Part of service interface, check permissions here */
public void setStreamVolumeWithAttribution(int streamType, int index, int flags,
String callingPackage, String attributionTag) {
+ if (mHardeningEnforcer.blockVolumeMethod(
+ HardeningEnforcer.METHOD_AUDIO_MANAGER_SET_STREAM_VOLUME)) {
+ return;
+ }
setStreamVolumeWithAttributionInt(streamType, index, flags, /*device*/ null,
callingPackage, attributionTag, true /*canChangeMuteAndUpdateController*/);
}
@@ -4457,6 +4482,18 @@ public class AudioService extends IAudioService.Stub
null /* playbackConfigs */, configs /* recordConfigs */);
}
+ private void dumpFlags(PrintWriter pw) {
+ pw.println("\nFun with Flags: ");
+ pw.println("\tandroid.media.audio.Flags.autoPublicVolumeApiHardening:"
+ + autoPublicVolumeApiHardening());
+ pw.println("\tandroid.media.audio.Flags.focusFreezeTestApi:"
+ + focusFreezeTestApi());
+ pw.println("\tcom.android.media.audio.Flags.bluetoothMacAddressAnonymization:"
+ + bluetoothMacAddressAnonymization());
+ pw.println("\tcom.android.media.audio.Flags.disablePrescaleAbsoluteVolume:"
+ + disablePrescaleAbsoluteVolume());
+ }
+
private void dumpAudioMode(PrintWriter pw) {
pw.println("\nAudio mode: ");
pw.println("- Requested mode = " + AudioSystem.modeToString(getMode()));
@@ -5081,6 +5118,7 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#setMasterMute(boolean, int) */
public void setMasterMute(boolean mute, int flags, String callingPackage, int userId,
String attributionTag) {
+
super.setMasterMute_enforcePermission();
setMasterMuteInternal(mute, flags, callingPackage,
@@ -5450,6 +5488,10 @@ public class AudioService extends IAudioService.Stub
}
public void setRingerModeExternal(int ringerMode, String caller) {
+ if (mHardeningEnforcer.blockVolumeMethod(
+ HardeningEnforcer.METHOD_AUDIO_MANAGER_SET_RINGER_MODE)) {
+ return;
+ }
if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
&& !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
throw new SecurityException("Not allowed to change Do Not Disturb state");
@@ -6202,6 +6244,35 @@ public class AudioService extends IAudioService.Stub
AudioDeviceVolumeManager.ADJUST_MODE_NORMAL);
}
+ /**
+ * @see AudioManager#adjustVolume(int, int)
+ * This method is redirected from AudioManager to AudioService for API hardening rules
+ * enforcement then to MediaSession for implementation.
+ */
+ @Override
+ public void adjustVolume(int direction, int flags) {
+ if (mHardeningEnforcer.blockVolumeMethod(
+ HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_VOLUME)) {
+ return;
+ }
+ getMediaSessionManager().dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
+ direction, flags);
+ }
+
+ /**
+ * @see AudioManager#adjustSuggestedStreamVolume(int, int, int)
+ * This method is redirected from AudioManager to AudioService for API hardening rules
+ * enforcement then to MediaSession for implementation.
+ */
+ @Override
+ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
+ if (mHardeningEnforcer.blockVolumeMethod(
+ HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_SUGGESTED_STREAM_VOLUME)) {
+ return;
+ }
+ getMediaSessionManager().dispatchAdjustVolume(suggestedStreamType, direction, flags);
+ }
+
/** @see AudioManager#setStreamVolumeForUid(int, int, int, String, int, int, int) */
@Override
public void setStreamVolumeForUid(int streamType, int index, int flags,
@@ -11405,6 +11476,7 @@ public class AudioService extends IAudioService.Stub
} else {
pw.println("\nMessage handler is null");
}
+ dumpFlags(pw);
mMediaFocusControl.dump(pw);
dumpStreamStates(pw);
dumpVolumeGroups(pw);
diff --git a/services/core/java/com/android/server/audio/HardeningEnforcer.java b/services/core/java/com/android/server/audio/HardeningEnforcer.java
new file mode 100644
index 000000000000..4ceb83b2e1c9
--- /dev/null
+++ b/services/core/java/com/android/server/audio/HardeningEnforcer.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.audio;
+
+import static android.media.audio.Flags.autoPublicVolumeApiHardening;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Class to encapsulate all audio API hardening operations
+ */
+public class HardeningEnforcer {
+
+ private static final String TAG = "AS.HardeningEnforcer";
+
+ final Context mContext;
+ final boolean mIsAutomotive;
+
+ /**
+ * Matches calls from {@link AudioManager#setStreamVolume(int, int, int)}
+ */
+ public static final int METHOD_AUDIO_MANAGER_SET_STREAM_VOLUME = 100;
+ /**
+ * Matches calls from {@link AudioManager#adjustVolume(int, int)}
+ */
+ public static final int METHOD_AUDIO_MANAGER_ADJUST_VOLUME = 101;
+ /**
+ * Matches calls from {@link AudioManager#adjustSuggestedStreamVolume(int, int, int)}
+ */
+ public static final int METHOD_AUDIO_MANAGER_ADJUST_SUGGESTED_STREAM_VOLUME = 102;
+ /**
+ * Matches calls from {@link AudioManager#adjustStreamVolume(int, int, int)}
+ */
+ public static final int METHOD_AUDIO_MANAGER_ADJUST_STREAM_VOLUME = 103;
+ /**
+ * Matches calls from {@link AudioManager#setRingerMode(int)}
+ */
+ public static final int METHOD_AUDIO_MANAGER_SET_RINGER_MODE = 200;
+
+ public HardeningEnforcer(Context ctxt, boolean isAutomotive) {
+ mContext = ctxt;
+ mIsAutomotive = isAutomotive;
+ }
+
+ /**
+ * Checks whether the call in the current thread should be allowed or blocked
+ * @param volumeMethod name of the method to check, for logging purposes
+ * @return false if the method call is allowed, true if it should be a no-op
+ */
+ protected boolean blockVolumeMethod(int volumeMethod) {
+ // for Auto, volume methods require MODIFY_AUDIO_SETTINGS_PRIVILEGED
+ if (mIsAutomotive) {
+ if (!autoPublicVolumeApiHardening()) {
+ // automotive hardening flag disabled, no blocking on auto
+ return false;
+ }
+ if (mContext.checkCallingOrSelfPermission(
+ Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ == PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ if (Binder.getCallingUid() < UserHandle.AID_APP_START) {
+ return false;
+ }
+ // TODO metrics?
+ // TODO log for audio dumpsys?
+ Log.e(TAG, "Preventing volume method " + volumeMethod + " for "
+ + getPackNameForUid(Binder.getCallingUid()));
+ return true;
+ }
+ // not blocking
+ return false;
+ }
+
+ private String getPackNameForUid(int uid) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final String[] names = mContext.getPackageManager().getPackagesForUid(uid);
+ if (names == null
+ || names.length == 0
+ || TextUtils.isEmpty(names[0])) {
+ return "[" + uid + "]";
+ }
+ return names[0];
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/BaseModeRefreshRateVote.java b/services/core/java/com/android/server/display/mode/BaseModeRefreshRateVote.java
new file mode 100644
index 000000000000..c04df64fc15a
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/BaseModeRefreshRateVote.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+import java.util.Objects;
+
+class BaseModeRefreshRateVote implements Vote {
+
+ /**
+ * The preferred refresh rate selected by the app. It is used to validate that the summary
+ * refresh rate ranges include this value, and are not restricted by a lower priority vote.
+ */
+ final float mAppRequestBaseModeRefreshRate;
+
+ BaseModeRefreshRateVote(float baseModeRefreshRate) {
+ mAppRequestBaseModeRefreshRate = baseModeRefreshRate;
+ }
+
+ @Override
+ public void updateSummary(DisplayModeDirector.VoteSummary summary) {
+ if (summary.appRequestBaseModeRefreshRate == 0f
+ && mAppRequestBaseModeRefreshRate > 0f) {
+ summary.appRequestBaseModeRefreshRate = mAppRequestBaseModeRefreshRate;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof BaseModeRefreshRateVote that)) return false;
+ return Float.compare(that.mAppRequestBaseModeRefreshRate,
+ mAppRequestBaseModeRefreshRate) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAppRequestBaseModeRefreshRate);
+ }
+
+ @Override
+ public String toString() {
+ return "BaseModeRefreshRateVote{ mAppRequestBaseModeRefreshRate="
+ + mAppRequestBaseModeRefreshRate + " }";
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/CombinedVote.java b/services/core/java/com/android/server/display/mode/CombinedVote.java
new file mode 100644
index 000000000000..f24fe3a7eb04
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/CombinedVote.java
@@ -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.server.display.mode;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+class CombinedVote implements Vote {
+ final List<Vote> mVotes;
+
+ CombinedVote(List<Vote> votes) {
+ mVotes = Collections.unmodifiableList(votes);
+ }
+
+ @Override
+ public void updateSummary(DisplayModeDirector.VoteSummary summary) {
+ mVotes.forEach(vote -> vote.updateSummary(summary));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof CombinedVote that)) return false;
+ return Objects.equals(mVotes, that.mVotes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mVotes);
+ }
+
+ @Override
+ public String toString() {
+ return "CombinedVote{ mVotes=" + mVotes + " }";
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/DisableRefreshRateSwitchingVote.java b/services/core/java/com/android/server/display/mode/DisableRefreshRateSwitchingVote.java
new file mode 100644
index 000000000000..2fc5590a4b94
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/DisableRefreshRateSwitchingVote.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+import java.util.Objects;
+
+class DisableRefreshRateSwitchingVote implements Vote {
+
+ /**
+ * Whether refresh rate switching should be disabled (i.e. the refresh rate range is
+ * a single value).
+ */
+ final boolean mDisableRefreshRateSwitching;
+
+ DisableRefreshRateSwitchingVote(boolean disableRefreshRateSwitching) {
+ mDisableRefreshRateSwitching = disableRefreshRateSwitching;
+ }
+
+ @Override
+ public void updateSummary(DisplayModeDirector.VoteSummary summary) {
+ summary.disableRefreshRateSwitching =
+ summary.disableRefreshRateSwitching || mDisableRefreshRateSwitching;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DisableRefreshRateSwitchingVote that)) return false;
+ return mDisableRefreshRateSwitching == that.mDisableRefreshRateSwitching;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDisableRefreshRateSwitching);
+ }
+
+ @Override
+ public String toString() {
+ return "DisableRefreshRateSwitchingVote{ mDisableRefreshRateSwitching="
+ + mDisableRefreshRateSwitching + " }";
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 9587f55b54dd..8eb03ec0d3bd 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -262,7 +262,7 @@ public class DisplayModeDirector {
mVotesStorage.setLoggingEnabled(loggingEnabled);
}
- private static final class VoteSummary {
+ static final class VoteSummary {
public float minPhysicalRefreshRate;
public float maxPhysicalRefreshRate;
public float minRenderFrameRate;
@@ -274,7 +274,12 @@ public class DisplayModeDirector {
public boolean disableRefreshRateSwitching;
public float appRequestBaseModeRefreshRate;
- VoteSummary() {
+ public List<SupportedModesVote.SupportedMode> supportedModes;
+
+ final boolean mIsDisplayResolutionRangeVotingEnabled;
+
+ VoteSummary(boolean isDisplayResolutionRangeVotingEnabled) {
+ mIsDisplayResolutionRangeVotingEnabled = isDisplayResolutionRangeVotingEnabled;
reset();
}
@@ -322,46 +327,7 @@ public class DisplayModeDirector {
continue;
}
- // For physical refresh rates, just use the tightest bounds of all the votes.
- // The refresh rate cannot be lower than the minimal render frame rate.
- final float minPhysicalRefreshRate = Math.max(vote.refreshRateRanges.physical.min,
- vote.refreshRateRanges.render.min);
- summary.minPhysicalRefreshRate = Math.max(summary.minPhysicalRefreshRate,
- minPhysicalRefreshRate);
- summary.maxPhysicalRefreshRate = Math.min(summary.maxPhysicalRefreshRate,
- vote.refreshRateRanges.physical.max);
-
- // Same goes to render frame rate, but frame rate cannot exceed the max physical
- // refresh rate
- final float maxRenderFrameRate = Math.min(vote.refreshRateRanges.render.max,
- vote.refreshRateRanges.physical.max);
- summary.minRenderFrameRate = Math.max(summary.minRenderFrameRate,
- vote.refreshRateRanges.render.min);
- summary.maxRenderFrameRate = Math.min(summary.maxRenderFrameRate, maxRenderFrameRate);
-
- // For display size, disable refresh rate switching and base mode refresh rate use only
- // the first vote we come across (i.e. the highest priority vote that includes the
- // attribute).
- if (vote.height > 0 && vote.width > 0) {
- if (summary.width == Vote.INVALID_SIZE && summary.height == Vote.INVALID_SIZE) {
- summary.width = vote.width;
- summary.height = vote.height;
- summary.minWidth = vote.minWidth;
- summary.minHeight = vote.minHeight;
- } else if (mIsDisplayResolutionRangeVotingEnabled) {
- summary.width = Math.min(summary.width, vote.width);
- summary.height = Math.min(summary.height, vote.height);
- summary.minWidth = Math.max(summary.minWidth, vote.minWidth);
- summary.minHeight = Math.max(summary.minHeight, vote.minHeight);
- }
- }
- if (!summary.disableRefreshRateSwitching && vote.disableRefreshRateSwitching) {
- summary.disableRefreshRateSwitching = true;
- }
- if (summary.appRequestBaseModeRefreshRate == 0f
- && vote.appRequestBaseModeRefreshRate > 0f) {
- summary.appRequestBaseModeRefreshRate = vote.appRequestBaseModeRefreshRate;
- }
+ vote.updateSummary(summary);
if (mLoggingEnabled) {
Slog.w(TAG, "Vote summary for priority " + Vote.priorityToString(priority)
@@ -443,7 +409,7 @@ public class DisplayModeDirector {
ArrayList<Display.Mode> availableModes = new ArrayList<>();
availableModes.add(defaultMode);
- VoteSummary primarySummary = new VoteSummary();
+ VoteSummary primarySummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled);
int lowestConsideredPriority = Vote.MIN_PRIORITY;
int highestConsideredPriority = Vote.MAX_PRIORITY;
@@ -526,7 +492,7 @@ public class DisplayModeDirector {
+ "]");
}
- VoteSummary appRequestSummary = new VoteSummary();
+ VoteSummary appRequestSummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled);
summarizeVotes(
votes,
Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF,
diff --git a/services/core/java/com/android/server/display/mode/RefreshRateVote.java b/services/core/java/com/android/server/display/mode/RefreshRateVote.java
new file mode 100644
index 000000000000..173b3c58cd95
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/RefreshRateVote.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+import java.util.Objects;
+
+
+/**
+ * Information about the refresh rate frame rate ranges DM would like to set the display to.
+ */
+abstract class RefreshRateVote implements Vote {
+ final float mMinRefreshRate;
+
+ final float mMaxRefreshRate;
+
+ RefreshRateVote(float minRefreshRate, float maxRefreshRate) {
+ mMinRefreshRate = minRefreshRate;
+ mMaxRefreshRate = maxRefreshRate;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof RefreshRateVote that)) return false;
+ return Float.compare(that.mMinRefreshRate, mMinRefreshRate) == 0
+ && Float.compare(that.mMaxRefreshRate, mMaxRefreshRate) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mMinRefreshRate, mMaxRefreshRate);
+ }
+
+ @Override
+ public String toString() {
+ return "RefreshRateVote{ mMinRefreshRate=" + mMinRefreshRate
+ + ", mMaxRefreshRate=" + mMaxRefreshRate + " }";
+ }
+
+ static class RenderVote extends RefreshRateVote {
+ RenderVote(float minRefreshRate, float maxRefreshRate) {
+ super(minRefreshRate, maxRefreshRate);
+ }
+
+ /**
+ * Summary: minRender minPhysical maxRender
+ * v v v
+ * -------------------|---------------------"-----------------------------|---------
+ * ^ ^ ^* ^ ^
+ * Vote: min(ignored) min(applied) min(applied+physical) max(applied) max(ignored)
+ */
+ @Override
+ public void updateSummary(DisplayModeDirector.VoteSummary summary) {
+ summary.minRenderFrameRate = Math.max(summary.minRenderFrameRate, mMinRefreshRate);
+ summary.maxRenderFrameRate = Math.min(summary.maxRenderFrameRate, mMaxRefreshRate);
+ // Physical refresh rate cannot be lower than the minimal render frame rate.
+ summary.minPhysicalRefreshRate = Math.max(summary.minPhysicalRefreshRate,
+ mMinRefreshRate);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof RefreshRateVote.RenderVote)) return false;
+ return super.equals(o);
+ }
+
+ @Override
+ public String toString() {
+ return "RenderVote{ " + super.toString() + " }";
+ }
+ }
+
+ static class PhysicalVote extends RefreshRateVote {
+ PhysicalVote(float minRefreshRate, float maxRefreshRate) {
+ super(minRefreshRate, maxRefreshRate);
+ }
+
+ /**
+ * Summary: minPhysical maxRender maxPhysical
+ * v v v
+ * -------------------"-----------------------------|----------------------"----------
+ * ^ ^ ^* ^ ^
+ * Vote: min(ignored) min(applied) max(applied+render) max(applied) max(ignored)
+ */
+ @Override
+ public void updateSummary(DisplayModeDirector.VoteSummary summary) {
+ summary.minPhysicalRefreshRate = Math.max(summary.minPhysicalRefreshRate,
+ mMinRefreshRate);
+ summary.maxPhysicalRefreshRate = Math.min(summary.maxPhysicalRefreshRate,
+ mMaxRefreshRate);
+ // Render frame rate cannot exceed the max physical refresh rate
+ summary.maxRenderFrameRate = Math.min(summary.maxRenderFrameRate, mMaxRefreshRate);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof RefreshRateVote.PhysicalVote)) return false;
+ return super.equals(o);
+ }
+
+ @Override
+ public String toString() {
+ return "PhysicalVote{ " + super.toString() + " }";
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/SizeVote.java b/services/core/java/com/android/server/display/mode/SizeVote.java
new file mode 100644
index 000000000000..a9b18a54a105
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/SizeVote.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+import java.util.Objects;
+
+class SizeVote implements Vote {
+
+ /**
+ * The requested width of the display in pixels;
+ */
+ final int mWidth;
+
+ /**
+ * The requested height of the display in pixels;
+ */
+ final int mHeight;
+
+ /**
+ * Min requested width of the display in pixels;
+ */
+ final int mMinWidth;
+
+ /**
+ * Min requested height of the display in pixels;
+ */
+ final int mMinHeight;
+
+ SizeVote(int width, int height, int minWidth, int minHeight) {
+ mWidth = width;
+ mHeight = height;
+ mMinWidth = minWidth;
+ mMinHeight = minHeight;
+ }
+
+ @Override
+ public void updateSummary(DisplayModeDirector.VoteSummary summary) {
+ if (mHeight > 0 && mWidth > 0) {
+ // For display size, disable refresh rate switching and base mode refresh rate use
+ // only the first vote we come across (i.e. the highest priority vote that includes
+ // the attribute).
+ if (summary.width == Vote.INVALID_SIZE && summary.height == Vote.INVALID_SIZE) {
+ summary.width = mWidth;
+ summary.height = mHeight;
+ summary.minWidth = mMinWidth;
+ summary.minHeight = mMinHeight;
+ } else if (summary.mIsDisplayResolutionRangeVotingEnabled) {
+ summary.width = Math.min(summary.width, mWidth);
+ summary.height = Math.min(summary.height, mHeight);
+ summary.minWidth = Math.max(summary.minWidth, mMinWidth);
+ summary.minHeight = Math.max(summary.minHeight, mMinHeight);
+ }
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SizeVote sizeVote)) return false;
+ return mWidth == sizeVote.mWidth && mHeight == sizeVote.mHeight
+ && mMinWidth == sizeVote.mMinWidth && mMinHeight == sizeVote.mMinHeight;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mWidth, mHeight, mMinWidth, mMinHeight);
+ }
+
+ @Override
+ public String toString() {
+ return "SizeVote{ mWidth=" + mWidth + ", mHeight=" + mHeight
+ + ", mMinWidth=" + mMinWidth + ", mMinHeight=" + mMinHeight + " }";
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/SupportedModesVote.java b/services/core/java/com/android/server/display/mode/SupportedModesVote.java
new file mode 100644
index 000000000000..b31461fc66b8
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/SupportedModesVote.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+class SupportedModesVote implements Vote {
+
+ final List<SupportedMode> mSupportedModes;
+
+ SupportedModesVote(List<SupportedMode> supportedModes) {
+ mSupportedModes = Collections.unmodifiableList(supportedModes);
+ }
+
+ /**
+ * Summary should have subset of supported modes.
+ * If Vote1.supportedModes=(A,B), Vote2.supportedModes=(B,C) then summary.supportedModes=(B)
+ * If summary.supportedModes==null then there is no restriction on supportedModes
+ */
+ @Override
+ public void updateSummary(DisplayModeDirector.VoteSummary summary) {
+ if (summary.supportedModes == null) {
+ summary.supportedModes = new ArrayList<>(mSupportedModes);
+ } else {
+ summary.supportedModes.retainAll(mSupportedModes);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SupportedModesVote that)) return false;
+ return mSupportedModes.equals(that.mSupportedModes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSupportedModes);
+ }
+
+ @Override
+ public String toString() {
+ return "SupportedModesVote{ mSupportedModes=" + mSupportedModes + " }";
+ }
+
+ static class SupportedMode {
+ final float mPeakRefreshRate;
+ final float mVsyncRate;
+
+
+ SupportedMode(float peakRefreshRate, float vsyncRate) {
+ mPeakRefreshRate = peakRefreshRate;
+ mVsyncRate = vsyncRate;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SupportedMode that)) return false;
+ return Float.compare(that.mPeakRefreshRate, mPeakRefreshRate) == 0
+ && Float.compare(that.mVsyncRate, mVsyncRate) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPeakRefreshRate, mVsyncRate);
+ }
+
+ @Override
+ public String toString() {
+ return "SupportedMode{ mPeakRefreshRate=" + mPeakRefreshRate
+ + ", mVsyncRate=" + mVsyncRate + " }";
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/Vote.java b/services/core/java/com/android/server/display/mode/Vote.java
index b6a6069b5a63..c1cdd6952dcc 100644
--- a/services/core/java/com/android/server/display/mode/Vote.java
+++ b/services/core/java/com/android/server/display/mode/Vote.java
@@ -16,15 +16,13 @@
package com.android.server.display.mode;
-import android.view.SurfaceControl;
+import java.util.List;
-import java.util.Objects;
-
-final class Vote {
+interface Vote {
// DEFAULT_RENDER_FRAME_RATE votes for render frame rate [0, DEFAULT]. As the lowest
// priority vote, it's overridden by all other considerations. It acts to set a default
// frame rate for a device.
- static final int PRIORITY_DEFAULT_RENDER_FRAME_RATE = 0;
+ int PRIORITY_DEFAULT_RENDER_FRAME_RATE = 0;
// PRIORITY_FLICKER_REFRESH_RATE votes for a single refresh rate like [60,60], [90,90] or
// null. It is used to set a preferred refresh rate value in case the higher priority votes
@@ -32,21 +30,21 @@ final class Vote {
static final int PRIORITY_FLICKER_REFRESH_RATE = 1;
// High-brightness-mode may need a specific range of refresh-rates to function properly.
- static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 2;
+ int PRIORITY_HIGH_BRIGHTNESS_MODE = 2;
// SETTING_MIN_RENDER_FRAME_RATE is used to propose a lower bound of the render frame rate.
// It votes [minRefreshRate, Float.POSITIVE_INFINITY]
- static final int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;
+ int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;
// User setting preferred display resolution.
- static final int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4;
+ int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4;
// APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
// frame rate in certain cases, mostly to preserve power.
// @see android.view.WindowManager.LayoutParams#preferredMinRefreshRate
// @see android.view.WindowManager.LayoutParams#preferredMaxRefreshRate
// It votes to [preferredMinRefreshRate, preferredMaxRefreshRate].
- static final int PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE = 5;
+ int PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE = 5;
// We split the app request into different priorities in case we can satisfy one desire
// without the other.
@@ -72,181 +70,100 @@ final class Vote {
// The preferred refresh rate is set on the main surface of the app outside of
// DisplayModeDirector.
// @see com.android.server.wm.WindowState#updateFrameRateSelectionPriorityIfNeeded
- static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 6;
+ int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 6;
- static final int PRIORITY_APP_REQUEST_SIZE = 7;
+ int PRIORITY_APP_REQUEST_SIZE = 7;
// SETTING_PEAK_RENDER_FRAME_RATE has a high priority and will restrict the bounds of the
// rest of low priority voters. It votes [0, max(PEAK, MIN)]
- static final int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 8;
+ int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 8;
// Restrict all displays to 60Hz when external display is connected. It votes [59Hz, 61Hz].
- static final int PRIORITY_SYNCHRONIZED_REFRESH_RATE = 9;
+ int PRIORITY_SYNCHRONIZED_REFRESH_RATE = 9;
// Restrict displays max available resolution and refresh rates. It votes [0, LIMIT]
- static final int PRIORITY_LIMIT_MODE = 10;
+ int PRIORITY_LIMIT_MODE = 10;
// To avoid delay in switching between 60HZ -> 90HZ when activating LHBM, set refresh
// rate to max value (same as for PRIORITY_UDFPS) on lock screen
- static final int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 11;
+ int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 11;
// For concurrent displays we want to limit refresh rate on all displays
- static final int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 12;
+ int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 12;
// LOW_POWER_MODE force the render frame rate to [0, 60HZ] if
// Settings.Global.LOW_POWER_MODE is on.
- static final int PRIORITY_LOW_POWER_MODE = 13;
+ int PRIORITY_LOW_POWER_MODE = 13;
// PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
// higher priority voters' result is a range, it will fix the rate to a single choice.
// It's used to avoid refresh rate switches in certain conditions which may result in the
// user seeing the display flickering when the switches occur.
- static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 14;
+ int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 14;
// Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
- static final int PRIORITY_SKIN_TEMPERATURE = 15;
+ int PRIORITY_SKIN_TEMPERATURE = 15;
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
// set to a high priority.
- static final int PRIORITY_PROXIMITY = 16;
+ int PRIORITY_PROXIMITY = 16;
// The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
// to function, so this needs to be the highest priority of all votes.
- static final int PRIORITY_UDFPS = 17;
+ int PRIORITY_UDFPS = 17;
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
- static final int MIN_PRIORITY = PRIORITY_DEFAULT_RENDER_FRAME_RATE;
- static final int MAX_PRIORITY = PRIORITY_UDFPS;
+ int MIN_PRIORITY = PRIORITY_DEFAULT_RENDER_FRAME_RATE;
+ int MAX_PRIORITY = PRIORITY_UDFPS;
// The cutoff for the app request refresh rate range. Votes with priorities lower than this
// value will not be considered when constructing the app request refresh rate range.
- static final int APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF =
+ int APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF =
PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE;
/**
* A value signifying an invalid width or height in a vote.
*/
- static final int INVALID_SIZE = -1;
+ int INVALID_SIZE = -1;
- /**
- * The requested width of the display in pixels, or INVALID_SIZE;
- */
- public final int width;
- /**
- * The requested height of the display in pixels, or INVALID_SIZE;
- */
- public final int height;
- /**
- * Min requested width of the display in pixels, or 0;
- */
- public final int minWidth;
- /**
- * Min requested height of the display in pixels, or 0;
- */
- public final int minHeight;
- /**
- * Information about the refresh rate frame rate ranges DM would like to set the display to.
- */
- public final SurfaceControl.RefreshRateRanges refreshRateRanges;
-
- /**
- * Whether refresh rate switching should be disabled (i.e. the refresh rate range is
- * a single value).
- */
- public final boolean disableRefreshRateSwitching;
-
- /**
- * The preferred refresh rate selected by the app. It is used to validate that the summary
- * refresh rate ranges include this value, and are not restricted by a lower priority vote.
- */
- public final float appRequestBaseModeRefreshRate;
+ void updateSummary(DisplayModeDirector.VoteSummary summary);
static Vote forPhysicalRefreshRates(float minRefreshRate, float maxRefreshRate) {
- return new Vote(/* minWidth= */ 0, /* minHeight= */ 0,
- /* width= */ INVALID_SIZE, /* height= */ INVALID_SIZE,
- /* minPhysicalRefreshRate= */ minRefreshRate,
- /* maxPhysicalRefreshRate= */ maxRefreshRate,
- /* minRenderFrameRate= */ 0,
- /* maxRenderFrameRate= */ Float.POSITIVE_INFINITY,
- /* disableRefreshRateSwitching= */ minRefreshRate == maxRefreshRate,
- /* baseModeRefreshRate= */ 0f);
+ return new CombinedVote(
+ List.of(
+ new RefreshRateVote.PhysicalVote(minRefreshRate, maxRefreshRate),
+ new DisableRefreshRateSwitchingVote(minRefreshRate == maxRefreshRate)
+ )
+ );
}
static Vote forRenderFrameRates(float minFrameRate, float maxFrameRate) {
- return new Vote(/* minWidth= */ 0, /* minHeight= */ 0,
- /* width= */ INVALID_SIZE, /* height= */ INVALID_SIZE,
- /* minPhysicalRefreshRate= */ 0,
- /* maxPhysicalRefreshRate= */ Float.POSITIVE_INFINITY,
- minFrameRate,
- maxFrameRate,
- /* disableRefreshRateSwitching= */ false,
- /* baseModeRefreshRate= */ 0f);
+ return new RefreshRateVote.RenderVote(minFrameRate, maxFrameRate);
}
static Vote forSize(int width, int height) {
- return new Vote(/* minWidth= */ width, /* minHeight= */ height,
- width, height,
- /* minPhysicalRefreshRate= */ 0,
- /* maxPhysicalRefreshRate= */ Float.POSITIVE_INFINITY,
- /* minRenderFrameRate= */ 0,
- /* maxRenderFrameRate= */ Float.POSITIVE_INFINITY,
- /* disableRefreshRateSwitching= */ false,
- /* baseModeRefreshRate= */ 0f);
+ return new SizeVote(width, height, width, height);
}
static Vote forSizeAndPhysicalRefreshRatesRange(int minWidth, int minHeight,
int width, int height, float minRefreshRate, float maxRefreshRate) {
- return new Vote(minWidth, minHeight,
- width, height,
- minRefreshRate,
- maxRefreshRate,
- /* minRenderFrameRate= */ 0,
- /* maxRenderFrameRate= */ Float.POSITIVE_INFINITY,
- /* disableRefreshRateSwitching= */ minRefreshRate == maxRefreshRate,
- /* baseModeRefreshRate= */ 0f);
+ return new CombinedVote(
+ List.of(
+ new SizeVote(width, height, minWidth, minHeight),
+ new RefreshRateVote.PhysicalVote(minRefreshRate, maxRefreshRate),
+ new DisableRefreshRateSwitchingVote(minRefreshRate == maxRefreshRate)
+ )
+ );
}
static Vote forDisableRefreshRateSwitching() {
- return new Vote(/* minWidth= */ 0, /* minHeight= */ 0,
- /* width= */ INVALID_SIZE, /* height= */ INVALID_SIZE,
- /* minPhysicalRefreshRate= */ 0,
- /* maxPhysicalRefreshRate= */ Float.POSITIVE_INFINITY,
- /* minRenderFrameRate= */ 0,
- /* maxRenderFrameRate= */ Float.POSITIVE_INFINITY,
- /* disableRefreshRateSwitching= */ true,
- /* baseModeRefreshRate= */ 0f);
+ return new DisableRefreshRateSwitchingVote(true);
}
static Vote forBaseModeRefreshRate(float baseModeRefreshRate) {
- return new Vote(/* minWidth= */ 0, /* minHeight= */ 0,
- /* width= */ INVALID_SIZE, /* height= */ INVALID_SIZE,
- /* minPhysicalRefreshRate= */ 0,
- /* maxPhysicalRefreshRate= */ Float.POSITIVE_INFINITY,
- /* minRenderFrameRate= */ 0,
- /* maxRenderFrameRate= */ Float.POSITIVE_INFINITY,
- /* disableRefreshRateSwitching= */ false,
- /* baseModeRefreshRate= */ baseModeRefreshRate);
- }
-
- private Vote(int minWidth, int minHeight,
- int width, int height,
- float minPhysicalRefreshRate,
- float maxPhysicalRefreshRate,
- float minRenderFrameRate,
- float maxRenderFrameRate,
- boolean disableRefreshRateSwitching,
- float baseModeRefreshRate) {
- this.minWidth = minWidth;
- this.minHeight = minHeight;
- this.width = width;
- this.height = height;
- this.refreshRateRanges = new SurfaceControl.RefreshRateRanges(
- new SurfaceControl.RefreshRateRange(minPhysicalRefreshRate, maxPhysicalRefreshRate),
- new SurfaceControl.RefreshRateRange(minRenderFrameRate, maxRenderFrameRate));
- this.disableRefreshRateSwitching = disableRefreshRateSwitching;
- this.appRequestBaseModeRefreshRate = baseModeRefreshRate;
+ return new BaseModeRefreshRateVote(baseModeRefreshRate);
}
static String priorityToString(int priority) {
@@ -291,33 +208,4 @@ final class Vote {
return Integer.toString(priority);
}
}
-
- @Override
- public String toString() {
- return "Vote: {"
- + "minWidth: " + minWidth + ", minHeight: " + minHeight
- + ", width: " + width + ", height: " + height
- + ", refreshRateRanges: " + refreshRateRanges
- + ", disableRefreshRateSwitching: " + disableRefreshRateSwitching
- + ", appRequestBaseModeRefreshRate: " + appRequestBaseModeRefreshRate + "}";
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(minWidth, minHeight, width, height, refreshRateRanges,
- disableRefreshRateSwitching, appRequestBaseModeRefreshRate);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof Vote)) return false;
- final var vote = (Vote) o;
- return minWidth == vote.minWidth && minHeight == vote.minHeight
- && width == vote.width && height == vote.height
- && disableRefreshRateSwitching == vote.disableRefreshRateSwitching
- && Float.compare(vote.appRequestBaseModeRefreshRate,
- appRequestBaseModeRefreshRate) == 0
- && refreshRateRanges.equals(vote.refreshRateRanges);
- }
}
diff --git a/services/core/java/com/android/server/display/mode/VotesStorage.java b/services/core/java/com/android/server/display/mode/VotesStorage.java
index 49c587aa5596..95fb8fc0947a 100644
--- a/services/core/java/com/android/server/display/mode/VotesStorage.java
+++ b/services/core/java/com/android/server/display/mode/VotesStorage.java
@@ -157,13 +157,19 @@ class VotesStorage {
}
}
- private int getMaxPhysicalRefreshRate(@Nullable Vote vote) {
+ private static int getMaxPhysicalRefreshRate(@Nullable Vote vote) {
if (vote == null) {
return -1;
- } else if (vote.refreshRateRanges.physical.max == Float.POSITIVE_INFINITY) {
- return 1000; // for visualisation, otherwise e.g. -1 -> 60 will be unnoticeable
+ } else if (vote instanceof RefreshRateVote.PhysicalVote physicalVote) {
+ return (int) physicalVote.mMaxRefreshRate;
+ } else if (vote instanceof CombinedVote combinedVote) {
+ return combinedVote.mVotes.stream()
+ .filter(v -> v instanceof RefreshRateVote.PhysicalVote)
+ .map(pv -> (int) (((RefreshRateVote.PhysicalVote) pv).mMaxRefreshRate))
+ .min(Integer::compare)
+ .orElse(1000); // for visualisation
}
- return (int) vote.refreshRateRanges.physical.max;
+ return 1000; // for visualisation, otherwise e.g. -1 -> 60 will be unnoticeable
}
interface Listener {
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 6a43697770cf..4821fbe1e6c0 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -2486,6 +2486,13 @@ class MediaRouter2ServiceImpl {
private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
long uniqueRequestId, int reason) {
if (handleSessionCreationRequestFailed(provider, uniqueRequestId, reason)) {
+ Slog.w(
+ TAG,
+ TextUtils.formatSimple(
+ "onRequestFailedOnHandler | Finished handling session creation"
+ + " request failed for provider: %s, uniqueRequestId: %d,"
+ + " reason: %d",
+ provider.getUniqueId(), uniqueRequestId, reason));
return;
}
@@ -2515,6 +2522,12 @@ class MediaRouter2ServiceImpl {
if (matchingRequest == null) {
// The failure is not about creating a session.
+ Slog.w(
+ TAG,
+ TextUtils.formatSimple(
+ "handleSessionCreationRequestFailed | No matching request found for"
+ + " provider: %s, uniqueRequestId: %d, reason: %d",
+ provider.getUniqueId(), uniqueRequestId, reason));
return false;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1b640fcb7e20..aa0b9b892220 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1765,8 +1765,7 @@ public class NotificationManagerService extends SystemService {
if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
// update system notification channels
SystemNotificationChannels.createAll(context);
- mZenModeHelper.updateDefaultZenRules(Binder.getCallingUid(),
- isCallerIsSystemOrSystemUi());
+ mZenModeHelper.updateDefaultZenRules(Binder.getCallingUid());
mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
}
}
@@ -3039,7 +3038,7 @@ public class NotificationManagerService extends SystemService {
mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true,
- Binder.getCallingUid(), isCallerIsSystemOrSystemUi());
+ Binder.getCallingUid(), isCallerSystemOrSystemUi());
if (mPreferencesHelper.onlyHasDefaultChannel(pkg, uid)) {
mPermissionHelper.setNotificationPermission(pkg, UserHandle.getUserId(uid),
channel.getImportance() != IMPORTANCE_NONE, true);
@@ -3087,7 +3086,7 @@ public class NotificationManagerService extends SystemService {
final NotificationChannelGroup preUpdate =
mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group,
- fromApp, Binder.getCallingUid(), isCallerIsSystemOrSystemUi());
+ fromApp, Binder.getCallingUid(), isCallerSystemOrSystemUi());
if (!fromApp) {
maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
}
@@ -3517,7 +3516,7 @@ public class NotificationManagerService extends SystemService {
}
checkCallerIsSameApp(pkg);
- final boolean isSystemToast = isCallerIsSystemOrSystemUi()
+ final boolean isSystemToast = isCallerSystemOrSystemUi()
|| PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
boolean isAppRenderedToast = (callback != null);
if (!checkCanEnqueueToast(pkg, callingUid, displayId, isAppRenderedToast,
@@ -4084,7 +4083,7 @@ public class NotificationManagerService extends SystemService {
channel, true /* fromTargetApp */,
mConditionProviders.isPackageOrComponentAllowed(
pkg, UserHandle.getUserId(uid)), Binder.getCallingUid(),
- isCallerIsSystemOrSystemUi());
+ isCallerSystemOrSystemUi());
if (needsPolicyFileChange) {
mListeners.notifyNotificationChannelChanged(pkg,
UserHandle.getUserHandleForUid(uid),
@@ -4165,7 +4164,7 @@ public class NotificationManagerService extends SystemService {
String targetPkg, String channelId, boolean returnParentIfNoConversationChannel,
String conversationId) {
if (canNotifyAsPackage(callingPkg, targetPkg, userId)
- || isCallerIsSystemOrSysemUiOrShell()) {
+ || isCallerSystemOrSystemUiOrShell()) {
int targetUid = -1;
try {
targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
@@ -4220,7 +4219,7 @@ public class NotificationManagerService extends SystemService {
public void deleteNotificationChannel(String pkg, String channelId) {
checkCallerIsSystemOrSameApp(pkg);
final int callingUid = Binder.getCallingUid();
- final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi();
+ final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
final int callingUser = UserHandle.getUserId(callingUid);
if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
throw new IllegalArgumentException("Cannot delete default channel");
@@ -4264,7 +4263,7 @@ public class NotificationManagerService extends SystemService {
checkCallerIsSystemOrSameApp(pkg);
final int callingUid = Binder.getCallingUid();
- final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi();
+ final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
NotificationChannelGroup groupToDelete =
mPreferencesHelper.getNotificationChannelGroupWithChannels(
pkg, callingUid, groupId, false);
@@ -5207,7 +5206,7 @@ public class NotificationManagerService extends SystemService {
public void requestInterruptionFilterFromListener(INotificationListener token,
int interruptionFilter) throws RemoteException {
final int callingUid = Binder.getCallingUid();
- final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi();
+ final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationLock) {
@@ -5254,7 +5253,7 @@ public class NotificationManagerService extends SystemService {
public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
enforceSystemOrSystemUI("INotificationManager.setZenMode");
final int callingUid = Binder.getCallingUid();
- final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi();
+ final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
final long identity = Binder.clearCallingIdentity();
try {
mZenModeHelper.setManualZenMode(mode, conditionId, null, reason, callingUid,
@@ -5316,7 +5315,9 @@ public class NotificationManagerService extends SystemService {
return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
"addAutomaticZenRule", Binder.getCallingUid(),
- isCallerIsSystemOrSystemUi());
+ // TODO: b/308670715: Distinguish FROM_APP from FROM_USER
+ isCallerSystemOrSystemUi() ? ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI
+ : ZenModeHelper.FROM_APP);
}
@Override
@@ -5334,7 +5335,9 @@ public class NotificationManagerService extends SystemService {
return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
"updateAutomaticZenRule", Binder.getCallingUid(),
- isCallerIsSystemOrSystemUi());
+ // TODO: b/308670715: Distinguish FROM_APP from FROM_USER
+ isCallerSystemOrSystemUi() ? ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI
+ : ZenModeHelper.FROM_APP);
}
@Override
@@ -5344,7 +5347,7 @@ public class NotificationManagerService extends SystemService {
enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule",
- Binder.getCallingUid(), isCallerIsSystemOrSystemUi());
+ Binder.getCallingUid(), isCallerSystemOrSystemUi());
}
@Override
@@ -5354,7 +5357,7 @@ public class NotificationManagerService extends SystemService {
return mZenModeHelper.removeAutomaticZenRules(packageName,
packageName + "|removeAutomaticZenRules", Binder.getCallingUid(),
- isCallerIsSystemOrSystemUi());
+ isCallerSystemOrSystemUi());
}
@Override
@@ -5373,7 +5376,7 @@ public class NotificationManagerService extends SystemService {
enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
mZenModeHelper.setAutomaticZenRuleState(id, condition, Binder.getCallingUid(),
- isCallerIsSystemOrSystemUi());
+ isCallerSystemOrSystemUi());
}
@Override
@@ -5382,7 +5385,7 @@ public class NotificationManagerService extends SystemService {
final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
final int callingUid = Binder.getCallingUid();
- final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi();
+ final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
if (android.app.Flags.modesApi() && !canManageGlobalZenPolicy(pkg, callingUid)) {
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(pkg, callingUid, zen);
@@ -5477,7 +5480,7 @@ public class NotificationManagerService extends SystemService {
() -> CompatChanges.isChangeEnabled(MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES,
callingUid));
return !isCompatChangeEnabled
- || isCallerIsSystemOrSystemUi()
+ || isCallerSystemOrSystemUi()
|| hasCompanionDevice(callingPkg, UserHandle.getUserId(callingUid),
AssociationRequest.DEVICE_PROFILE_WATCH);
}
@@ -5708,7 +5711,7 @@ public class NotificationManagerService extends SystemService {
public void setNotificationPolicy(String pkg, Policy policy) {
enforcePolicyAccess(pkg, "setNotificationPolicy");
int callingUid = Binder.getCallingUid();
- boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi();
+ boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
boolean shouldApplyAsImplicitRule = android.app.Flags.modesApi()
&& !canManageGlobalZenPolicy(pkg, callingUid);
@@ -7110,7 +7113,7 @@ public class NotificationManagerService extends SystemService {
}
mPreferencesHelper.updateNotificationChannel(
pkg, notificationUid, channel, false, callingUid,
- isCallerIsSystemOrSystemUi());
+ isCallerSystemOrSystemUi());
r.updateNotificationChannel(channel);
} else if (!channel.isUserVisibleTaskShown() && !TextUtils.isEmpty(channelId)
&& !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
@@ -10430,7 +10433,7 @@ public class NotificationManagerService extends SystemService {
}
@VisibleForTesting
- protected boolean isCallerIsSystemOrSystemUi() {
+ protected boolean isCallerSystemOrSystemUi() {
if (isCallerSystemOrPhone()) {
return true;
}
@@ -10438,12 +10441,12 @@ public class NotificationManagerService extends SystemService {
== PERMISSION_GRANTED;
}
- private boolean isCallerIsSystemOrSysemUiOrShell() {
+ private boolean isCallerSystemOrSystemUiOrShell() {
int callingUid = Binder.getCallingUid();
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
return true;
}
- return isCallerIsSystemOrSystemUi();
+ return isCallerSystemOrSystemUi();
}
private void checkCallerIsSystemOrShell() {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 2ef0ca64c9d6..89d820050b03 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -27,6 +27,7 @@ import static android.service.notification.NotificationServiceProto.ROOT_CONFIG;
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
@@ -73,6 +74,7 @@ import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
+import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
import android.service.notification.ZenModeProto;
@@ -105,6 +107,8 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -129,6 +133,21 @@ public class ZenModeHelper {
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
static final long SEND_ACTIVATION_AZR_STATUSES = 308673617L;
+ /** A rule addition or update that is initiated by the System or SystemUI. */
+ static final int FROM_SYSTEM_OR_SYSTEMUI = 1;
+ /** A rule addition or update that is initiated by the user (through system settings). */
+ static final int FROM_USER = 2;
+ /** A rule addition or update that is initiated by an app (via NotificationManager APIs). */
+ static final int FROM_APP = 3;
+
+ @IntDef(prefix = { "FROM_" }, value = {
+ FROM_SYSTEM_OR_SYSTEMUI,
+ FROM_USER,
+ FROM_APP
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface ChangeOrigin {}
+
// pkg|userId => uid
@VisibleForTesting protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>();
@@ -378,7 +397,7 @@ public class ZenModeHelper {
}
public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule,
- String reason, int callingUid, boolean fromSystemOrSystemUi) {
+ String reason, int callingUid, @ChangeOrigin int origin) {
if (!ZenModeConfig.SYSTEM_AUTHORITY.equals(pkg)) {
PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner());
if (component == null) {
@@ -412,10 +431,10 @@ public class ZenModeHelper {
}
newConfig = mConfig.copy();
ZenRule rule = new ZenRule();
- populateZenRule(pkg, automaticZenRule, rule, true);
+ populateZenRule(pkg, automaticZenRule, rule, true, origin);
newConfig.automaticRules.put(rule.id, rule);
if (setConfigLocked(newConfig, reason, rule.component, true, callingUid,
- fromSystemOrSystemUi)) {
+ origin == FROM_SYSTEM_OR_SYSTEMUI)) {
return rule.id;
} else {
throw new AndroidRuntimeException("Could not create rule");
@@ -424,7 +443,7 @@ public class ZenModeHelper {
}
public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
- String reason, int callingUid, boolean fromSystemOrSystemUi) {
+ String reason, int callingUid, @ChangeOrigin int origin) {
ZenModeConfig newConfig;
synchronized (mConfigLock) {
if (mConfig == null) return false;
@@ -452,9 +471,9 @@ public class ZenModeHelper {
}
}
- populateZenRule(rule.pkg, automaticZenRule, rule, false);
+ populateZenRule(rule.pkg, automaticZenRule, rule, false, origin);
return setConfigLocked(newConfig, reason, rule.component, true, callingUid,
- fromSystemOrSystemUi);
+ origin == FROM_SYSTEM_OR_SYSTEMUI);
}
}
@@ -790,7 +809,7 @@ public class ZenModeHelper {
}
}
- protected void updateDefaultZenRules(int callingUid, boolean fromSystemOrSystemUi) {
+ protected void updateDefaultZenRules(int callingUid) {
updateDefaultAutomaticRuleNames();
synchronized (mConfigLock) {
for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) {
@@ -807,7 +826,7 @@ public class ZenModeHelper {
// update default rule (if locale changed, name of rule will change)
currRule.name = defaultRule.name;
updateAutomaticZenRule(defaultRule.id, zenRuleToAutomaticZenRule(currRule),
- "locale changed", callingUid, fromSystemOrSystemUi);
+ "locale changed", callingUid, FROM_SYSTEM_OR_SYSTEMUI);
}
}
}
@@ -850,7 +869,11 @@ public class ZenModeHelper {
}
private static void populateZenRule(String pkg, AutomaticZenRule automaticZenRule, ZenRule rule,
- boolean isNew) {
+ boolean isNew, @ChangeOrigin int origin) {
+ // TODO: b/308671593,b/311406021 - Handle origins more precisely:
+ // - FROM_USER can override anything and updates bitmask of user-modified fields;
+ // - FROM_SYSTEM_OR_SYSTEMUI can override anything and preserves bitmask;
+ // - FROM_APP can only update if not user-modified.
if (rule.enabled != automaticZenRule.isEnabled()) {
rule.snoozing = false;
}
@@ -861,7 +884,10 @@ public class ZenModeHelper {
rule.modified = automaticZenRule.isModified();
rule.zenPolicy = automaticZenRule.getZenPolicy();
if (Flags.modesApi()) {
- rule.zenDeviceEffects = automaticZenRule.getDeviceEffects();
+ rule.zenDeviceEffects = fixZenDeviceEffects(
+ rule.zenDeviceEffects,
+ automaticZenRule.getDeviceEffects(),
+ origin);
}
rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
@@ -882,6 +908,50 @@ public class ZenModeHelper {
}
}
+ /** "
+ * Fix" {@link ZenDeviceEffects} that are being stored as part of a new or updated ZenRule.
+ *
+ * <ul>
+ * <li> Apps cannot turn on hidden effects (those tagged as {@code @hide}) since they are
+ * intended for platform-specific rules (e.g. wearables). If it's a new rule, we blank them
+ * out; if it's an update, we preserve the previous values.
+ * </ul>
+ */
+ @Nullable
+ private static ZenDeviceEffects fixZenDeviceEffects(@Nullable ZenDeviceEffects oldEffects,
+ @Nullable ZenDeviceEffects newEffects, @ChangeOrigin int origin) {
+ // TODO: b/308671593,b/311406021 - Handle origins more precisely:
+ // - FROM_USER can override anything and updates bitmask of user-modified fields;
+ // - FROM_SYSTEM_OR_SYSTEMUI can override anything and preserves bitmask;
+ // - FROM_APP can only update if not user-modified.
+ if (origin == FROM_SYSTEM_OR_SYSTEMUI || origin == FROM_USER) {
+ return newEffects;
+ }
+
+ if (newEffects == null) {
+ return null;
+ }
+ if (oldEffects != null) {
+ return new ZenDeviceEffects.Builder(newEffects)
+ .setShouldDisableAutoBrightness(oldEffects.shouldDisableAutoBrightness())
+ .setShouldDisableTapToWake(oldEffects.shouldDisableTapToWake())
+ .setShouldDisableTiltToWake(oldEffects.shouldDisableTiltToWake())
+ .setShouldDisableTouch(oldEffects.shouldDisableTouch())
+ .setShouldMinimizeRadioUsage(oldEffects.shouldMinimizeRadioUsage())
+ .setShouldMaximizeDoze(oldEffects.shouldMaximizeDoze())
+ .build();
+ } else {
+ return new ZenDeviceEffects.Builder(newEffects)
+ .setShouldDisableAutoBrightness(false)
+ .setShouldDisableTapToWake(false)
+ .setShouldDisableTiltToWake(false)
+ .setShouldDisableTouch(false)
+ .setShouldMinimizeRadioUsage(false)
+ .setShouldMaximizeDoze(false)
+ .build();
+ }
+ }
+
private static AutomaticZenRule zenRuleToAutomaticZenRule(ZenRule rule) {
AutomaticZenRule azr;
if (Flags.modesApi()) {
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 3caff11e0a3a..448f215bb029 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -154,6 +154,7 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.F2fsUtils;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
@@ -175,7 +176,6 @@ import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.Permission;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index fc831205f60e..0a81b2b9fabb 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -50,9 +50,9 @@ import android.util.ArrayMap;
import android.util.ExceptionUtils;
import android.util.Slog;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.util.ArrayUtils;
import com.android.server.art.model.DexoptResult;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index 6faf68dc560c..c66a9e98c1d3 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -22,7 +22,7 @@ import android.util.ArraySet;
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e557f09467d4..233bf4f9394c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -181,6 +181,8 @@ import com.android.internal.app.ResolverActivity;
import com.android.internal.content.F2fsUtils;
import com.android.internal.content.InstallLocationUtils;
import com.android.internal.content.om.OverlayConfig;
+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.telephony.CarrierAppUtils;
@@ -220,9 +222,7 @@ import com.android.server.pm.dex.DynamicCodeLogger;
import com.android.server.pm.local.PackageManagerLocalImpl;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackageInternal;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
import com.android.server.pm.permission.LegacyPermissionManagerService;
import com.android.server.pm.permission.LegacyPermissionSettings;
@@ -5216,6 +5216,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)) {
+ return null;
+ }
+ return mSuspendPackageHelper.getSuspendingPackage(snapshot, packageName, userId,
+ callingUid);
+ }
+
+ @Override
public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() {
// allow instant applications
ArrayList<FeatureInfo> res;
diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
index 434a62da88c9..15d2fdc35f2b 100644
--- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java
+++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
@@ -41,10 +41,10 @@ import android.util.apk.ApkSignatureVerifier;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.InstallLocationUtils;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.rollback.RollbackManagerInternal;
import java.io.File;
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index b50d0a07aa3a..293b87317ced 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -44,9 +44,9 @@ import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.AndroidPackageInternal;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
-import com.android.server.pm.parsing.pkg.AndroidPackageInternal;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.permission.LegacyPermissionState;
@@ -1732,7 +1732,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
time = 1700251133016L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
- inputSignatures = "private int mBooleans\nprivate int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate long mLoadingCompletedTime\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate @android.annotation.Nullable java.lang.String mAppMetadataFilePath\nprivate int mTargetSdkVersion\nprivate @android.annotation.Nullable byte[] mRestrictUpdateHash\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackage(java.lang.String,int)\npublic com.android.server.pm.PackageSetting setUpdateOwnerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic com.android.server.pm.PackageSetting setSharedUserAppId(int)\npublic com.android.server.pm.PackageSetting setTargetSdkVersion(int)\npublic com.android.server.pm.PackageSetting setRestrictUpdateHash(byte[])\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprivate void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic boolean isRequestLegacyExternalStorage()\npublic boolean isUserDataFragile()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n boolean isInstalledOrHasDataOnAnyOtherUser(int[],int)\n int[] queryInstalledUsers(int[],boolean)\n int[] queryUsersInstalledOrHasData(int[])\n long getCeDataInode(int)\n long getDeDataInode(int)\n void setCeDataInode(long,int)\n void setDeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\npublic com.android.server.pm.PackageSetting setScannedAsStoppedSystemApp(boolean)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long,int,com.android.server.pm.pkg.ArchiveState)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\nprivate static void writeArchiveState(android.util.proto.ProtoOutputStream,com.android.server.pm.pkg.ArchiveState)\npublic @com.android.internal.annotations.VisibleForTesting com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isIncremental()\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic com.android.server.pm.PackageSetting setLoadingCompletedTime(long)\npublic com.android.server.pm.PackageSetting setAppMetadataFilePath(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.server.pm.pkg.SharedLibrary> getSharedLibraryDependencies()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryInfo(android.content.pm.SharedLibraryInfo)\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryFile(java.lang.String)\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getApexModuleName()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic com.android.server.pm.PackageSetting setApexModuleName(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbi()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbi()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getSeInfo()\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbiLegacy()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbiLegacy()\npublic @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy @java.lang.Override int getHiddenApiEnforcementPolicy()\npublic @java.lang.Override boolean isApex()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isDefaultToDeviceProtectedStorage()\npublic @java.lang.Override boolean isPersistent()\npublic @java.lang.Override boolean isScannedAsStoppedSystemApp()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\nprivate static final int INSTALL_PERMISSION_FIXED\nprivate static final int UPDATE_AVAILABLE\nprivate static final int FORCE_QUERYABLE_OVERRIDE\nprivate static final int SCANNED_AS_STOPPED_SYSTEM_APP\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+ inputSignatures = "private int mBooleans\nprivate int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.internal.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate long mLoadingCompletedTime\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate @android.annotation.Nullable java.lang.String mAppMetadataFilePath\nprivate int mTargetSdkVersion\nprivate @android.annotation.Nullable byte[] mRestrictUpdateHash\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackage(java.lang.String,int)\npublic com.android.server.pm.PackageSetting setUpdateOwnerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic com.android.server.pm.PackageSetting setSharedUserAppId(int)\npublic com.android.server.pm.PackageSetting setTargetSdkVersion(int)\npublic com.android.server.pm.PackageSetting setRestrictUpdateHash(byte[])\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprivate void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic boolean isRequestLegacyExternalStorage()\npublic boolean isUserDataFragile()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n boolean isInstalledOrHasDataOnAnyOtherUser(int[],int)\n int[] queryInstalledUsers(int[],boolean)\n int[] queryUsersInstalledOrHasData(int[])\n long getCeDataInode(int)\n long getDeDataInode(int)\n void setCeDataInode(long,int)\n void setDeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\npublic com.android.server.pm.PackageSetting setScannedAsStoppedSystemApp(boolean)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long,int,com.android.server.pm.pkg.ArchiveState)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\nprivate static void writeArchiveState(android.util.proto.ProtoOutputStream,com.android.server.pm.pkg.ArchiveState)\npublic @com.android.internal.annotations.VisibleForTesting com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isIncremental()\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic com.android.server.pm.PackageSetting setLoadingCompletedTime(long)\npublic com.android.server.pm.PackageSetting setAppMetadataFilePath(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.server.pm.pkg.SharedLibrary> getSharedLibraryDependencies()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryInfo(android.content.pm.SharedLibraryInfo)\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryFile(java.lang.String)\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getApexModuleName()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic com.android.server.pm.PackageSetting setApexModuleName(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbi()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbi()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getSeInfo()\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbiLegacy()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbiLegacy()\npublic @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy @java.lang.Override int getHiddenApiEnforcementPolicy()\npublic @java.lang.Override boolean isApex()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isDefaultToDeviceProtectedStorage()\npublic @java.lang.Override boolean isPersistent()\npublic @java.lang.Override boolean isScannedAsStoppedSystemApp()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\nprivate static final int INSTALL_PERMISSION_FIXED\nprivate static final int UPDATE_AVAILABLE\nprivate static final int FORCE_QUERYABLE_OVERRIDE\nprivate static final int SCANNED_AS_STOPPED_SYSTEM_APP\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 56258844a3fe..1089ac943802 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -22,9 +22,9 @@ import android.os.Process;
import android.os.Trace;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.util.ConcurrentUtils;
import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import java.io.File;
import java.util.concurrent.ArrayBlockingQueue;
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 5312ae6ca84c..bb0017c80d6d 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -30,7 +30,7 @@ import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedLongSparseArray;
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 22ee963cf9a2..53b84e66840b 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -73,6 +73,7 @@ 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.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedProcess;
@@ -83,7 +84,6 @@ import com.android.server.SystemConfig;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateUtils;
import com.android.server.pm.pkg.component.ComponentMutateUtils;
diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java
index e66a72f0fccb..37cf30bd63fe 100644
--- a/services/core/java/com/android/server/pm/ScanRequest.java
+++ b/services/core/java/com/android/server/pm/ScanRequest.java
@@ -21,7 +21,7 @@ import android.annotation.Nullable;
import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 585e2e48fb85..d0fdfa9bc775 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -46,11 +46,11 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.utils.Snappable;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 85563172cf05..f90bf4b47644 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1957,6 +1957,19 @@ public class UserManagerService extends IUserManager.Stub {
return userTypeDetails.getStatusBarIcon();
}
+ @Override
+ public @StringRes int getProfileLabelResId(@UserIdInt int userId) {
+ checkQueryOrInteractPermissionIfCallerInOtherProfileGroup(userId,
+ "getProfileLabelResId");
+ final UserInfo userInfo = getUserInfoNoChecks(userId);
+ final UserTypeDetails userTypeDetails = getUserTypeDetails(userInfo);
+ if (userInfo == null || userTypeDetails == null) {
+ return Resources.ID_NULL;
+ }
+ final int userIndex = userInfo.profileBadge;
+ return userTypeDetails.getLabel(userIndex);
+ }
+
public boolean isProfile(@UserIdInt int userId) {
checkQueryOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isProfile");
return isProfileUnchecked(userId);
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index 7bdcd685a2e9..56c400a0caf8 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -54,8 +54,15 @@ public final class UserTypeDetails {
/** Whether users of this type can be created. */
private final boolean mEnabled;
- // TODO(b/142482943): Currently unused and not set. Hook this up.
- private final int mLabel;
+ /**
+ * Resource IDs ({@link StringRes}) of the user's labels. This might be used to label a
+ * user/profile in tabbed views, etc.
+ * The values are resource IDs referring to the strings not the strings themselves.
+ *
+ * <p>This is an array because, in general, there may be multiple users of the same user type.
+ * In this case, the user is indexed according to its {@link UserInfo#profileBadge}.
+ */
+ private final @Nullable int[] mLabels;
/**
* Maximum number of this user type allowed on the device.
@@ -160,8 +167,8 @@ public final class UserTypeDetails {
private final @NonNull UserProperties mDefaultUserProperties;
private UserTypeDetails(@NonNull String name, boolean enabled, int maxAllowed,
- @UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags, int label,
- int maxAllowedPerParent,
+ @UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags,
+ @Nullable int[] labels, int maxAllowedPerParent,
int iconBadge, int badgePlain, int badgeNoBackground,
int statusBarIcon,
@Nullable int[] badgeLabels, @Nullable int[] badgeColors,
@@ -181,12 +188,11 @@ public final class UserTypeDetails {
this.mDefaultSystemSettings = defaultSystemSettings;
this.mDefaultSecureSettings = defaultSecureSettings;
this.mDefaultCrossProfileIntentFilters = defaultCrossProfileIntentFilters;
-
this.mIconBadge = iconBadge;
this.mBadgePlain = badgePlain;
this.mBadgeNoBackground = badgeNoBackground;
this.mStatusBarIcon = statusBarIcon;
- this.mLabel = label;
+ this.mLabels = labels;
this.mBadgeLabels = badgeLabels;
this.mBadgeColors = badgeColors;
this.mDarkThemeBadgeColors = darkThemeBadgeColors;
@@ -234,9 +240,16 @@ public final class UserTypeDetails {
return mDefaultUserInfoPropertyFlags | mBaseType;
}
- // TODO(b/142482943) Hook this up; it is currently unused.
- public int getLabel() {
- return mLabel;
+ /**
+ * Returns the resource ID corresponding to the badgeIndexth label name where the badgeIndex is
+ * expected to be the {@link UserInfo#profileBadge} of the user. If badgeIndex exceeds the
+ * number of labels, returns the label for the highest index.
+ */
+ public @StringRes int getLabel(int badgeIndex) {
+ if (mLabels == null || mLabels.length == 0 || badgeIndex < 0) {
+ return Resources.ID_NULL;
+ }
+ return mLabels[Math.min(badgeIndex, mLabels.length - 1)];
}
/** Returns whether users of this user type should be badged. */
@@ -358,7 +371,6 @@ public final class UserTypeDetails {
pw.print(prefix); pw.print("mMaxAllowedPerParent: "); pw.println(mMaxAllowedPerParent);
pw.print(prefix); pw.print("mDefaultUserInfoFlags: ");
pw.println(UserInfo.flagsToString(mDefaultUserInfoPropertyFlags));
- pw.print(prefix); pw.print("mLabel: "); pw.println(mLabel);
mDefaultUserProperties.println(pw, prefix);
final String restrictionsPrefix = prefix + " ";
@@ -392,6 +404,8 @@ public final class UserTypeDetails {
pw.println(mBadgeColors != null ? mBadgeColors.length : "0(null)");
pw.print(prefix); pw.print("mDarkThemeBadgeColors.length: ");
pw.println(mDarkThemeBadgeColors != null ? mDarkThemeBadgeColors.length : "0(null)");
+ pw.print(prefix); pw.print("mLabels.length: ");
+ pw.println(mLabels != null ? mLabels.length : "0(null)");
}
/** Builder for a {@link UserTypeDetails}; see that class for documentation. */
@@ -408,7 +422,7 @@ public final class UserTypeDetails {
private @Nullable List<DefaultCrossProfileIntentFilter> mDefaultCrossProfileIntentFilters =
null;
private int mEnabled = 1;
- private int mLabel = Resources.ID_NULL;
+ private @Nullable int[] mLabels = null;
private @Nullable int[] mBadgeLabels = null;
private @Nullable int[] mBadgeColors = null;
private @Nullable int[] mDarkThemeBadgeColors = null;
@@ -488,8 +502,8 @@ public final class UserTypeDetails {
return this;
}
- public Builder setLabel(int label) {
- mLabel = label;
+ public Builder setLabels(@StringRes int ... labels) {
+ mLabels = labels;
return this;
}
@@ -562,7 +576,7 @@ public final class UserTypeDetails {
mMaxAllowed,
mBaseType,
mDefaultUserInfoPropertyFlags,
- mLabel,
+ mLabels,
mMaxAllowedPerParent,
mIconBadge,
mBadgePlain,
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 7da76c18216e..4ef8cb780734 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -128,7 +128,7 @@ public final class UserTypeFactory {
.setName(USER_TYPE_PROFILE_CLONE)
.setBaseType(FLAG_PROFILE)
.setMaxAllowedPerParent(1)
- .setLabel(0)
+ .setLabels(R.string.profile_label_clone)
.setIconBadge(com.android.internal.R.drawable.ic_clone_icon_badge)
.setBadgePlain(com.android.internal.R.drawable.ic_clone_badge)
// Clone doesn't use BadgeNoBackground, so just set to BadgePlain as a placeholder.
@@ -154,6 +154,10 @@ public final class UserTypeFactory {
UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
.setCrossProfileIntentResolutionStrategy(UserProperties
.CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING)
+ .setShowInQuietMode(
+ UserProperties.SHOW_IN_QUIET_MODE_DEFAULT)
+ .setShowInSharingSurfaces(
+ UserProperties.SHOW_IN_SHARING_SURFACES_WITH_PARENT)
.setMediaSharedWithParent(true)
.setCredentialShareableWithParent(true)
.setDeleteAppWithParent(true));
@@ -169,7 +173,10 @@ public final class UserTypeFactory {
.setBaseType(FLAG_PROFILE)
.setDefaultUserInfoPropertyFlags(FLAG_MANAGED_PROFILE)
.setMaxAllowedPerParent(1)
- .setLabel(0)
+ .setLabels(
+ R.string.profile_label_work,
+ R.string.profile_label_work_2,
+ R.string.profile_label_work_3)
.setIconBadge(com.android.internal.R.drawable.ic_corp_icon_badge_case)
.setBadgePlain(com.android.internal.R.drawable.ic_corp_badge_case)
.setBadgeNoBackground(com.android.internal.R.drawable.ic_corp_badge_no_background)
@@ -193,6 +200,10 @@ public final class UserTypeFactory {
.setStartWithParent(true)
.setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
.setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
+ .setShowInQuietMode(
+ UserProperties.SHOW_IN_QUIET_MODE_PAUSED)
+ .setShowInSharingSurfaces(
+ UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE)
.setAuthAlwaysRequiredToDisableQuietMode(false)
.setCredentialShareableWithParent(true));
}
@@ -209,7 +220,10 @@ public final class UserTypeFactory {
.setName(USER_TYPE_PROFILE_TEST)
.setBaseType(FLAG_PROFILE)
.setMaxAllowedPerParent(2)
- .setLabel(0)
+ .setLabels(
+ R.string.profile_label_test,
+ R.string.profile_label_test,
+ R.string.profile_label_test)
.setIconBadge(com.android.internal.R.drawable.ic_test_icon_badge_experiment)
.setBadgePlain(com.android.internal.R.drawable.ic_test_badge_experiment)
.setBadgeNoBackground(com.android.internal.R.drawable.ic_test_badge_no_background)
@@ -240,7 +254,7 @@ public final class UserTypeFactory {
.setBaseType(FLAG_PROFILE)
.setMaxAllowed(1)
.setEnabled(UserManager.isCommunalProfileEnabled() ? 1 : 0)
- .setLabel(0)
+ .setLabels(R.string.profile_label_communal)
.setIconBadge(com.android.internal.R.drawable.ic_test_icon_badge_experiment)
.setBadgePlain(com.android.internal.R.drawable.ic_test_badge_experiment)
.setBadgeNoBackground(com.android.internal.R.drawable.ic_test_badge_no_background)
@@ -276,7 +290,7 @@ public final class UserTypeFactory {
.setName(USER_TYPE_PROFILE_PRIVATE)
.setBaseType(FLAG_PROFILE)
.setMaxAllowedPerParent(1)
- .setLabel(0)
+ .setLabels(R.string.profile_label_private)
.setIconBadge(com.android.internal.R.drawable.ic_private_profile_icon_badge)
.setBadgePlain(com.android.internal.R.drawable.ic_private_profile_badge)
// Private Profile doesn't use BadgeNoBackground, so just set to BadgePlain
@@ -298,7 +312,10 @@ public final class UserTypeFactory {
.setMediaSharedWithParent(false)
.setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
.setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
- .setHideInSettingsInQuietMode(true)
+ .setShowInQuietMode(
+ UserProperties.SHOW_IN_QUIET_MODE_HIDDEN)
+ .setShowInSharingSurfaces(
+ UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE)
.setCrossProfileIntentFilterAccessControl(
UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
.setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT));
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 2ab7db47f8e5..459e2cf7f5c0 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.ParsedPackage;
import com.android.server.pm.ApexManager;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import libcore.io.IoUtils;
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 3b10c7f2c2a6..1c751e07bbbe 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -35,12 +35,12 @@ import android.util.DisplayMetrics;
import android.util.Slog;
import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.internal.util.ArrayUtils;
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.parsing.pkg.ParsedPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.parsing.ParsingUtils;
diff --git a/services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java
index 8b5719ac7712..f4e187f578cb 100644
--- a/services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java
@@ -21,7 +21,7 @@ import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_H
import android.os.Build;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
/**
* Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java
diff --git a/services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java
index adaa04cb9335..34880a8d4c24 100644
--- a/services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java
@@ -16,7 +16,7 @@
package com.android.server.pm.parsing.library;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
/**
* Updates a package to remove dependency on android.net.ipsec.ike library.
diff --git a/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
index 3b29d1f9b881..97e30207f683 100644
--- a/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
@@ -29,8 +29,8 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
/**
diff --git a/services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java b/services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java
index 041b77b88789..0c38c6006266 100644
--- a/services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java
@@ -19,9 +19,9 @@ package com.android.server.pm.parsing.library;
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.modules.utils.build.UnboundedSdkLevel;
import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
/**
* Updates packages to add or remove dependencies on shared libraries as per attributes
diff --git a/services/core/java/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdater.java b/services/core/java/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdater.java
index b47a768e61b7..1c6c1fba1b93 100644
--- a/services/core/java/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdater.java
@@ -16,7 +16,7 @@
package com.android.server.pm.parsing.library;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
/**
* Updates a package to remove dependency on com.google.android.maps library.
diff --git a/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java b/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
index ac65c8c9f338..b5589818bf67 100644
--- a/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
@@ -20,7 +20,7 @@ import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACH
import android.os.Build;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
/**
diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
index 3da71414f8fc..fe9cd0eec4a6 100644
--- a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
+++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
@@ -24,9 +24,9 @@ import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACH
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
import java.util.ArrayList;
import java.util.List;
diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java b/services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java
index a9c22d9e6bb9..a5af0059cdf3 100644
--- a/services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java
@@ -19,8 +19,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import java.util.ArrayList;
import java.util.List;
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 0eb2bbde5886..61be6e1036f2 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,17 +29,18 @@ import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.incremental.IncrementalManager;
import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.pm.parsing.pkg.AndroidPackageHidden;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedProvider;
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;
-import com.android.server.pm.pkg.parsing.ParsingPackageHidden;
import java.io.IOException;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index c8ac6982071b..85d95eab2958 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -50,6 +50,10 @@ 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.pkg.AndroidPackageSplitImpl;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
import com.android.internal.pm.pkg.component.ParsedAttribution;
@@ -63,6 +67,8 @@ 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.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
@@ -71,7 +77,6 @@ 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.AndroidPackageSplitImpl;
import com.android.server.pm.pkg.SELinuxUtil;
import com.android.server.pm.pkg.component.ComponentMutateUtils;
import com.android.server.pm.pkg.component.ParsedActivityImpl;
@@ -84,8 +89,6 @@ 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.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageHidden;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.parsing.ParsingUtils;
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6f6bb45bad50..f7f76aaaee16 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -807,7 +807,7 @@ final class DefaultPermissionGrantPolicy {
getDefaultSystemHandlerActivityPackage(pm,
SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
- NOTIFICATION_PERMISSIONS);
+ NOTIFICATION_PERMISSIONS, PHONE_PERMISSIONS);
}
// Voice recognition
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
index fc74a195eb49..c73728393016 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
@@ -22,9 +22,9 @@ import android.annotation.UserIdInt;
import android.content.pm.SigningDetails;
import android.util.SparseArray;
+import com.android.internal.pm.parsing.pkg.AndroidPackageInternal;
import com.android.server.pm.InstallSource;
import com.android.server.pm.PackageKeySetData;
-import com.android.server.pm.parsing.pkg.AndroidPackageInternal;
import com.android.server.pm.permission.LegacyPermissionState;
import java.util.UUID;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java b/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java
index 041edaa98e63..019ca1315af8 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java
@@ -32,9 +32,9 @@ 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.ParsingPackage;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.parsing.ParsingUtils;
diff --git a/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java b/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java
index 14976848fe61..dd54cfca6518 100644
--- a/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java
+++ b/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java
@@ -26,8 +26,8 @@ import android.os.Build;
import android.util.ArraySet;
import com.android.internal.R;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.SystemConfig;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
index 5709cbb09f93..64985bdfd54f 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
@@ -49,8 +49,8 @@ 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.util.ArrayUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.parsing.ParsingUtils;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java
index c6b9b1a166b6..9322cf0e90f6 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java
@@ -31,7 +31,7 @@ import android.text.TextUtils;
import android.util.TypedValue;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.parsing.ParsingUtils;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java
index 9792a91fb699..a7116949b911 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java
@@ -27,7 +27,7 @@ import android.content.res.XmlResourceParser;
import com.android.internal.R;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
+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/ParsedIntentInfoUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java
index 5e67bbf4ab0b..e5e214d2292b 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java
@@ -32,7 +32,7 @@ import android.util.TypedValue;
import com.android.internal.R;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.parsing.ParsingUtils;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java
index 6c22f825bab9..8268f0fdfa3e 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java
@@ -33,7 +33,7 @@ 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.server.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
index 0f2b49b8541c..4b45d3742a2a 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
@@ -33,7 +33,7 @@ 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.server.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java
index 766fb90cbfa0..a84954950f44 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java
@@ -28,9 +28,9 @@ 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.util.CollectionUtils;
import com.android.internal.util.XmlUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
index b66db4f9ced4..0b28a1214072 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
@@ -35,7 +35,7 @@ import android.util.Slog;
import com.android.internal.R;
import com.android.internal.pm.pkg.component.ParsedProvider;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
index 1b421841f166..171ef594f6fd 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
@@ -33,7 +33,7 @@ import android.os.Build;
import com.android.internal.R;
import com.android.internal.pm.pkg.component.ParsedService;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index e4594c58f40f..722350a0d7fb 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -89,6 +89,7 @@ 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.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
import com.android.internal.pm.pkg.component.ParsedAttribution;
@@ -102,11 +103,11 @@ 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.ParsingPackage;
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.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.CompatibilityPermissionInfo;
import com.android.server.pm.pkg.component.ComponentMutateUtils;
import com.android.server.pm.pkg.component.ComponentParseUtils;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
index 2cfffb3b185d..1d159554e8a7 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
@@ -31,6 +31,7 @@ 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.util.Parcelling;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 986735f5f2ee..73c422490330 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3537,7 +3537,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mDisplayManager.setBrightness(screenDisplayId, adjustedLinearBrightness);
Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION
+ | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
intent.putExtra(EXTRA_FROM_BRIGHTNESS_KEY, true);
startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
logKeyboardSystemsEvent(event, KeyboardLogEvent.getBrightnessEvent(keyCode));
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 68f554cb2758..ea8a801ff697 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -16,6 +16,8 @@
package com.android.server.webkit;
+import static android.webkit.Flags.updateServiceV2;
+
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.content.Context;
@@ -237,18 +239,30 @@ public class SystemImpl implements SystemInterface {
@Override
public int getMultiProcessSetting(Context context) {
- return Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.WEBVIEW_MULTIPROCESS, 0);
+ if (updateServiceV2()) {
+ throw new IllegalStateException(
+ "getMultiProcessSetting shouldn't be called if update_service_v2 flag is set.");
+ }
+ return Settings.Global.getInt(
+ context.getContentResolver(), Settings.Global.WEBVIEW_MULTIPROCESS, 0);
}
@Override
public void setMultiProcessSetting(Context context, int value) {
- Settings.Global.putInt(context.getContentResolver(),
- Settings.Global.WEBVIEW_MULTIPROCESS, value);
+ if (updateServiceV2()) {
+ throw new IllegalStateException(
+ "setMultiProcessSetting shouldn't be called if update_service_v2 flag is set.");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), Settings.Global.WEBVIEW_MULTIPROCESS, value);
}
@Override
public void notifyZygote(boolean enableMultiProcess) {
+ if (updateServiceV2()) {
+ throw new IllegalStateException(
+ "notifyZygote shouldn't be called if update_service_v2 flag is set.");
+ }
WebViewZygote.setMultiprocessEnabled(enableMultiProcess);
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index b3672ecb194c..b12da61d0b3f 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -157,8 +157,13 @@ public class WebViewUpdateService extends SystemService {
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
- (new WebViewUpdateServiceShellCommand(this)).exec(
- this, in, out, err, args, callback, resultReceiver);
+ if (updateServiceV2()) {
+ (new WebViewUpdateServiceShellCommand2(this))
+ .exec(this, in, out, err, args, callback, resultReceiver);
+ } else {
+ (new WebViewUpdateServiceShellCommand(this))
+ .exec(this, in, out, err, args, callback, resultReceiver);
+ }
}
@@ -275,18 +280,31 @@ public class WebViewUpdateService extends SystemService {
@Override // Binder call
public boolean isMultiProcessEnabled() {
+ if (updateServiceV2()) {
+ throw new IllegalStateException(
+ "isMultiProcessEnabled shouldn't be called if update_service_v2 flag is"
+ + " set.");
+ }
return WebViewUpdateService.this.mImpl.isMultiProcessEnabled();
}
@Override // Binder call
public void enableMultiProcess(boolean enable) {
- if (getContext().checkCallingPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ if (updateServiceV2()) {
+ throw new IllegalStateException(
+ "enableMultiProcess shouldn't be called if update_service_v2 flag is set.");
+ }
+ if (getContext()
+ .checkCallingPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS)
!= PackageManager.PERMISSION_GRANTED) {
- String msg = "Permission Denial: enableMultiProcess() from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
- + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
+ String msg =
+ "Permission Denial: enableMultiProcess() from pid="
+ + Binder.getCallingPid()
+ + ", uid="
+ + Binder.getCallingUid()
+ + " requires "
+ + android.Manifest.permission.WRITE_SECURE_SETTINGS;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
index e618c7e2a80c..89cb4c802410 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
@@ -23,6 +23,7 @@ import android.content.pm.Signature;
import android.os.AsyncTask;
import android.os.Trace;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Slog;
import android.webkit.UserPackage;
import android.webkit.WebViewFactory;
@@ -70,10 +71,6 @@ class WebViewUpdateServiceImpl2 implements WebViewUpdateServiceInterface {
WebViewPackageMissingException(String message) {
super(message);
}
-
- WebViewPackageMissingException(Exception e) {
- super(e);
- }
}
private static final int WAIT_TIMEOUT_MS = 1000; // KEY_DISPATCHING_TIMEOUT is 5000.
@@ -85,9 +82,6 @@ class WebViewUpdateServiceImpl2 implements WebViewUpdateServiceInterface {
private static final int VALIDITY_INCORRECT_SIGNATURE = 3;
private static final int VALIDITY_NO_LIBRARY_FLAG = 4;
- private static final int MULTIPROCESS_SETTING_ON_VALUE = Integer.MAX_VALUE;
- private static final int MULTIPROCESS_SETTING_OFF_VALUE = Integer.MIN_VALUE;
-
private final SystemInterface mSystemInterface;
private final Context mContext;
@@ -166,7 +160,6 @@ class WebViewUpdateServiceImpl2 implements WebViewUpdateServiceInterface {
@Override
public void prepareWebViewInSystemServer() {
- mSystemInterface.notifyZygote(isMultiProcessEnabled());
try {
synchronized (mLock) {
mCurrentWebViewPackage = findPreferredWebViewPackage();
@@ -366,14 +359,10 @@ class WebViewUpdateServiceImpl2 implements WebViewUpdateServiceInterface {
// Once we've notified the system that the provider has changed and started RELRO creation,
// try to restart the zygote so that it will be ready when apps use it.
- if (isMultiProcessEnabled()) {
- AsyncTask.THREAD_POOL_EXECUTOR.execute(this::startZygoteWhenReady);
- }
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(this::startZygoteWhenReady);
}
- /**
- * Fetch only the currently valid WebView packages.
- **/
+ /** Fetch only the currently valid WebView packages. */
@Override
public WebViewProviderInfo[] getValidWebViewPackages() {
ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
@@ -632,62 +621,56 @@ class WebViewUpdateServiceImpl2 implements WebViewUpdateServiceInterface {
@Override
public boolean isMultiProcessEnabled() {
- int settingValue = mSystemInterface.getMultiProcessSetting(mContext);
- if (mSystemInterface.isMultiProcessDefaultEnabled()) {
- // Multiprocess should be enabled unless the user has turned it off manually.
- return settingValue > MULTIPROCESS_SETTING_OFF_VALUE;
- } else {
- // Multiprocess should not be enabled, unless the user has turned it on manually.
- return settingValue >= MULTIPROCESS_SETTING_ON_VALUE;
- }
+ throw new IllegalStateException(
+ "isMultiProcessEnabled shouldn't be called if update_service_v2 flag is set.");
}
@Override
public void enableMultiProcess(boolean enable) {
- PackageInfo current = getCurrentWebViewPackage();
- mSystemInterface.setMultiProcessSetting(mContext,
- enable ? MULTIPROCESS_SETTING_ON_VALUE : MULTIPROCESS_SETTING_OFF_VALUE);
- mSystemInterface.notifyZygote(enable);
- if (current != null) {
- mSystemInterface.killPackageDependents(current.packageName);
- }
+ throw new IllegalStateException(
+ "enableMultiProcess shouldn't be called if update_service_v2 flag is set.");
}
- /**
- * Dump the state of this Service.
- */
+ /** Dump the state of this Service. */
@Override
public void dumpState(PrintWriter pw) {
pw.println("Current WebView Update Service state");
- pw.println(String.format(" Multiprocess enabled: %b", isMultiProcessEnabled()));
synchronized (mLock) {
if (mCurrentWebViewPackage == null) {
pw.println(" Current WebView package is null");
} else {
- pw.println(String.format(" Current WebView package (name, version): (%s, %s)",
- mCurrentWebViewPackage.packageName,
- mCurrentWebViewPackage.versionName));
+ pw.println(
+ TextUtils.formatSimple(
+ " Current WebView package (name, version): (%s, %s)",
+ mCurrentWebViewPackage.packageName,
+ mCurrentWebViewPackage.versionName));
}
- pw.println(String.format(" Minimum targetSdkVersion: %d",
- UserPackage.MINIMUM_SUPPORTED_SDK));
- pw.println(String.format(" Minimum WebView version code: %d",
- mMinimumVersionCode));
- pw.println(String.format(" Number of relros started: %d",
- mNumRelroCreationsStarted));
- pw.println(String.format(" Number of relros finished: %d",
- mNumRelroCreationsFinished));
- pw.println(String.format(" WebView package dirty: %b", mWebViewPackageDirty));
- pw.println(String.format(" Any WebView package installed: %b",
- mAnyWebViewInstalled));
+ pw.println(
+ TextUtils.formatSimple(
+ " Minimum targetSdkVersion: %d", UserPackage.MINIMUM_SUPPORTED_SDK));
+ pw.println(
+ TextUtils.formatSimple(
+ " Minimum WebView version code: %d", mMinimumVersionCode));
+ pw.println(
+ TextUtils.formatSimple(
+ " Number of relros started: %d", mNumRelroCreationsStarted));
+ pw.println(
+ TextUtils.formatSimple(
+ " Number of relros finished: %d", mNumRelroCreationsFinished));
+ pw.println(TextUtils.formatSimple(" WebView package dirty: %b", mWebViewPackageDirty));
+ pw.println(
+ TextUtils.formatSimple(
+ " Any WebView package installed: %b", mAnyWebViewInstalled));
try {
PackageInfo preferredWebViewPackage = findPreferredWebViewPackage();
- pw.println(String.format(
- " Preferred WebView package (name, version): (%s, %s)",
- preferredWebViewPackage.packageName,
- preferredWebViewPackage.versionName));
+ pw.println(
+ TextUtils.formatSimple(
+ " Preferred WebView package (name, version): (%s, %s)",
+ preferredWebViewPackage.packageName,
+ preferredWebViewPackage.versionName));
} catch (WebViewPackageMissingException e) {
- pw.println(String.format(" Preferred WebView package: none"));
+ pw.println(" Preferred WebView package: none");
}
dumpAllPackageInformationLocked(pw);
@@ -703,29 +686,36 @@ class WebViewUpdateServiceImpl2 implements WebViewUpdateServiceInterface {
PackageInfo systemUserPackageInfo =
userPackages.get(UserHandle.USER_SYSTEM).getPackageInfo();
if (systemUserPackageInfo == null) {
- pw.println(String.format(" %s is NOT installed.", provider.packageName));
+ pw.println(
+ TextUtils.formatSimple(" %s is NOT installed.", provider.packageName));
continue;
}
int validity = validityResult(provider, systemUserPackageInfo);
- String packageDetails = String.format(
- "versionName: %s, versionCode: %d, targetSdkVersion: %d",
- systemUserPackageInfo.versionName,
- systemUserPackageInfo.getLongVersionCode(),
- systemUserPackageInfo.applicationInfo.targetSdkVersion);
+ String packageDetails =
+ TextUtils.formatSimple(
+ "versionName: %s, versionCode: %d, targetSdkVersion: %d",
+ systemUserPackageInfo.versionName,
+ systemUserPackageInfo.getLongVersionCode(),
+ systemUserPackageInfo.applicationInfo.targetSdkVersion);
if (validity == VALIDITY_OK) {
- boolean installedForAllUsers = isInstalledAndEnabledForAllUsers(
- mSystemInterface.getPackageInfoForProviderAllUsers(mContext, provider));
- pw.println(String.format(
- " Valid package %s (%s) is %s installed/enabled for all users",
- systemUserPackageInfo.packageName,
- packageDetails,
- installedForAllUsers ? "" : "NOT"));
+ boolean installedForAllUsers =
+ isInstalledAndEnabledForAllUsers(
+ mSystemInterface.getPackageInfoForProviderAllUsers(
+ mContext, provider));
+ pw.println(
+ TextUtils.formatSimple(
+ " Valid package %s (%s) is %s installed/enabled for all users",
+ systemUserPackageInfo.packageName,
+ packageDetails,
+ installedForAllUsers ? "" : "NOT"));
} else {
- pw.println(String.format(" Invalid package %s (%s), reason: %s",
- systemUserPackageInfo.packageName,
- packageDetails,
- getInvalidityReason(validity)));
+ pw.println(
+ TextUtils.formatSimple(
+ " Invalid package %s (%s), reason: %s",
+ systemUserPackageInfo.packageName,
+ packageDetails,
+ getInvalidityReason(validity)));
}
}
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand2.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand2.java
new file mode 100644
index 000000000000..ce95b1857b27
--- /dev/null
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand2.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.webkit;
+
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.text.TextUtils;
+import android.webkit.IWebViewUpdateService;
+
+import java.io.PrintWriter;
+
+class WebViewUpdateServiceShellCommand2 extends ShellCommand {
+ final IWebViewUpdateService mInterface;
+
+ WebViewUpdateServiceShellCommand2(IWebViewUpdateService service) {
+ mInterface = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ switch (cmd) {
+ case "set-webview-implementation":
+ return setWebViewImplementation();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (RemoteException e) {
+ pw.println("Remote exception: " + e);
+ }
+ return -1;
+ }
+
+ private int setWebViewImplementation() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ String shellChosenPackage = getNextArg();
+ if (shellChosenPackage == null) {
+ pw.println("Failed to switch, no PACKAGE provided.");
+ pw.println("");
+ helpSetWebViewImplementation();
+ return 1;
+ }
+ String newPackage = mInterface.changeProviderAndSetting(shellChosenPackage);
+ if (shellChosenPackage.equals(newPackage)) {
+ pw.println("Success");
+ return 0;
+ } else {
+ pw.println(
+ TextUtils.formatSimple(
+ "Failed to switch to %s, the WebView implementation is now provided by"
+ + " %s.",
+ shellChosenPackage, newPackage));
+ return 1;
+ }
+ }
+
+ public void helpSetWebViewImplementation() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println(" set-webview-implementation PACKAGE");
+ pw.println(" Set the WebView implementation to the specified package.");
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("WebView updater commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println("");
+ helpSetWebViewImplementation();
+ pw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 849836828d94..75e6faf97294 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2731,7 +2731,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* Receive the splash screen data from shell, sending to client.
* @param parcelable The data to reconstruct the splash screen view, null mean unable to copy.
*/
- void onCopySplashScreenFinish(SplashScreenViewParcelable parcelable) {
+ void onCopySplashScreenFinish(@Nullable SplashScreenViewParcelable parcelable) {
removeTransferSplashScreenTimeout();
final SurfaceControl windowAnimationLeash = (parcelable == null
|| mTransferringSplashScreenState != TRANSFER_SPLASH_SCREEN_COPYING
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 34c7eee45f34..6f5c676187e1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3618,8 +3618,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
* @hide
*/
@Override
- public void onSplashScreenViewCopyFinished(int taskId, SplashScreenViewParcelable parcelable)
- throws RemoteException {
+ public void onSplashScreenViewCopyFinished(int taskId,
+ @Nullable SplashScreenViewParcelable parcelable)
+ throws RemoteException {
mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_TASKS,
"copySplashScreenViewFinish()");
synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 43f32096b6c0..be7b8559e39e 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -429,9 +429,12 @@ class BackNavigationController {
final TaskFragment prevTFAdjacent = prevTF.getAdjacentTaskFragment();
if (prevTFAdjacent != null) {
if (prevTFAdjacent == currTF) {
- // Cannot predict what will happen when app receive back key, skip animation.
outPrevActivities.clear();
- return false;
+ // No more activity in task, so it can predict if previous task exists.
+ // Otherwise, unable to predict what will happen when app receive
+ // back key, skip animation.
+ return currentTask.getActivity((below) -> !below.finishing, prevActivity,
+ false /*includeBoundary*/, true /*traverseTopToBottom*/) == null;
} else {
final ActivityRecord prevActivityAdjacent =
prevTFAdjacent.getTopNonFinishingActivity();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index d65d778549cc..522e7d205a00 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -627,7 +627,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
void refreshSecureSurfaceState() {
forAllWindows((w) -> {
if (w.mHasSurface) {
- w.mWinAnimator.setSecureLocked(w.isSecureLocked());
+ w.setSecureLocked(w.isSecureLocked());
}
}, true /* traverseTopToBottom */);
}
@@ -2171,12 +2171,16 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// now, it will take focus briefly which confuses the RecentTasks tracker.
rootTask.setWindowingMode(WINDOWING_MODE_PINNED);
}
-
+ // Temporarily disable focus when reparenting to avoid intermediate focus change
+ // (because the task is on top and the activity is resumed), which could cause the
+ // task to be added in recents task list unexpectedly.
+ rootTask.setFocusable(false);
// There are multiple activities in the task and moving the top activity should
// reveal/leave the other activities in their original task.
// On the other hand, ActivityRecord#onParentChanged takes care of setting the
// up-to-dated root pinned task information on this newly created root task.
r.reparent(rootTask, MAX_VALUE, reason);
+ rootTask.setFocusable(true);
// Ensure the leash of new task is in sync with its current bounds after reparent.
rootTask.maybeApplyLastRecentsAnimationTransaction();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 575ae69be12b..dd2b48bb5a3d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2327,8 +2327,8 @@ public class WindowManagerService extends IWindowManager.Stub
boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
&& win.hasWallpaper();
wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0;
- if ((flagChanges & FLAG_SECURE) != 0 && winAnimator.mSurfaceController != null) {
- winAnimator.mSurfaceController.setSecure(win.isSecureLocked());
+ if ((flagChanges & FLAG_SECURE) != 0) {
+ win.setSecureLocked(win.isSecureLocked());
}
final boolean wasVisible = win.isVisible();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3e43908994ad..e1f1f662c5aa 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -109,6 +109,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RESIZE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
@@ -177,6 +178,7 @@ import static com.android.server.wm.WindowStateProto.UNRESTRICTED_KEEP_CLEAR_ARE
import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES;
+import static com.android.window.flags.Flags.secureWindowState;
import static com.android.window.flags.Flags.surfaceTrustedOverlay;
import android.annotation.CallSuper;
@@ -1195,6 +1197,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (surfaceTrustedOverlay() && isWindowTrustedOverlay()) {
getPendingTransaction().setTrustedOverlay(mSurfaceControl, true);
}
+ if (secureWindowState()) {
+ getPendingTransaction().setSecure(mSurfaceControl, isSecureLocked());
+ }
}
void updateTrustedOverlay() {
@@ -3276,7 +3281,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// just kill it. And if it is a window of foreground activity, the activity can be
// restarted automatically if needed.
Slog.w(TAG, "Exception thrown during dispatchAppVisibility " + this, e);
- android.os.Process.killProcess(mSession.mPid);
+ if (android.os.Process.getUidForPid(mSession.mPid) == mSession.mUid) {
+ android.os.Process.killProcess(mSession.mPid);
+ }
}
}
@@ -6040,4 +6047,25 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Cancel any draw requests during a sync.
return mPrepareSyncSeqId > 0;
}
+
+ void setSecureLocked(boolean isSecure) {
+ ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isSecure=%b: %s", isSecure, getName());
+ if (secureWindowState()) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+ getPendingTransaction().setSecure(mSurfaceControl, isSecure);
+ } else {
+ if (mWinAnimator.mSurfaceController == null
+ || mWinAnimator.mSurfaceController.mSurfaceControl == null) {
+ return;
+ }
+ getPendingTransaction().setSecure(mWinAnimator.mSurfaceController.mSurfaceControl,
+ isSecure);
+ }
+ if (mDisplayContent != null) {
+ mDisplayContent.refreshImeSecureFlag(getSyncTransaction());
+ }
+ mWmService.scheduleAnimationLocked();
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 3aac816fcd7a..44cd23d037c6 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -44,6 +44,7 @@ import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE;
import static com.android.server.wm.WindowStateAnimatorProto.SURFACE;
import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
+import static com.android.window.flags.Flags.secureWindowState;
import android.content.Context;
import android.graphics.PixelFormat;
@@ -286,8 +287,10 @@ class WindowStateAnimator {
int flags = SurfaceControl.HIDDEN;
final WindowManager.LayoutParams attrs = w.mAttrs;
- if (w.isSecureLocked()) {
- flags |= SurfaceControl.SECURE;
+ if (!secureWindowState()) {
+ if (w.isSecureLocked()) {
+ flags |= SurfaceControl.SECURE;
+ }
}
if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
@@ -488,13 +491,6 @@ class WindowStateAnimator {
mSurfaceController.setOpaque(isOpaque);
}
- void setSecureLocked(boolean isSecure) {
- if (mSurfaceController == null) {
- return;
- }
- mSurfaceController.setSecure(isSecure);
- }
-
void setColorSpaceAgnosticLocked(boolean agnostic) {
if (mSurfaceController == null) {
return;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index d348491b3d2a..4456a94ef510 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -24,7 +24,6 @@ import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowSurfaceControllerProto.SHOWN;
@@ -152,24 +151,6 @@ class WindowSurfaceController {
mService.scheduleAnimationLocked();
}
- void setSecure(boolean isSecure) {
- ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isSecure=%b: %s", isSecure, title);
-
- if (mSurfaceControl == null) {
- return;
- }
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setSecureLocked");
-
- final SurfaceControl.Transaction t = mAnimator.mWin.getPendingTransaction();
- t.setSecure(mSurfaceControl, isSecure);
-
- final DisplayContent dc = mAnimator.mWin.mDisplayContent;
- if (dc != null) {
- dc.refreshImeSecureFlag(t);
- }
- mService.scheduleAnimationLocked();
- }
-
void setColorSpaceAgnostic(SurfaceControl.Transaction t, boolean agnostic) {
ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isColorSpaceAgnostic=%b: %s", agnostic, title);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9b62a2c41655..e0a2f30b1831 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -18182,7 +18182,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static boolean hasAccountFeatures(AccountManager am, Account account,
String[] features) {
try {
- return am.hasFeatures(account, features, null, null).getResult();
+ return am.hasFeatures(account, features, null, null)
+ .getResult(30, TimeUnit.SECONDS);
} catch (Exception e) {
Slogf.w(LOG_TAG, "Failed to get account feature", e);
return false;
diff --git a/services/permission/OWNERS b/services/permission/OWNERS
index e464038e68d9..487c992bbab4 100644
--- a/services/permission/OWNERS
+++ b/services/permission/OWNERS
@@ -1,5 +1,3 @@
#Bug component: 137825
-joecastro@google.com
-ntmyren@google.com
-zhanghai@google.com
+include platform/frameworks/base:/core/java/android/permission/OWNERS
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index 4e468362177a..d62da1a02525 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.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.parsing.pkg.ParsedPackage;
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 8d76fddcc793..3011fa17d4fc 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
@@ -24,6 +24,8 @@ import android.content.pm.PackageManager
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.ParsedPackage
import com.android.internal.pm.pkg.component.ParsedActivity
import com.android.server.pm.AppsFilterImpl
import com.android.server.pm.PackageManagerService
@@ -36,9 +38,7 @@ 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.AndroidPackageInternal
import com.android.server.pm.parsing.pkg.PackageImpl
-import com.android.server.pm.parsing.pkg.ParsedPackage
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.resolution.ComponentResolver
import com.android.server.pm.snapshot.PackageDataSnapshot
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 25146a87970f..3461bb6b2c55 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,11 +49,12 @@ import android.util.SparseArray;
import androidx.annotation.NonNull;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedPermission;
+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.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.component.ParsedActivityImpl;
import com.android.server.pm.pkg.component.ParsedComponentImpl;
@@ -62,7 +63,6 @@ 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.pm.pkg.parsing.ParsingPackage;
import com.android.server.utils.WatchableTester;
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 2810145c08a9..a0dc2b68415c 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.ParsedPackage;
import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.LocalServices;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
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 7552800d8b0e..9c48af8ecd01 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
@@ -72,7 +72,7 @@ import androidx.test.filters.Suppress;
import com.android.compatibility.common.util.CddTest;
import com.android.internal.content.InstallLocationUtils;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
+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;
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 7c28e13f0eee..ea88ec25b26e 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
@@ -58,6 +58,7 @@ import androidx.test.filters.MediumTest;
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.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
import com.android.internal.pm.pkg.component.ParsedComponent;
@@ -68,6 +69,7 @@ import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
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.ParsingPackage;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageInfoUtils;
@@ -75,7 +77,6 @@ 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.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.CompatibilityPermissionInfo;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageUserStateInternal;
@@ -88,7 +89,6 @@ 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 com.android.server.pm.pkg.parsing.ParsingPackage;
import org.junit.Before;
import org.junit.Rule;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ParallelPackageParserTest.java
index 38d01d0c4c18..8a74e24a3810 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -21,9 +21,9 @@ import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.TestPackageParser2;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import junit.framework.Assert;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanRequestBuilder.java
index 1c3673e84038..2a8e5b18bda3 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanRequestBuilder.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanRequestBuilder.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.UserHandle;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
class ScanRequestBuilder {
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 e2939c1aff3b..decb44c2cd9b 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.ParsedPackage;
+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.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import org.hamcrest.BaseMatcher;
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 7123c2076640..b102ab4f7e3b 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
@@ -38,12 +38,12 @@ import androidx.test.InstrumentationRegistry;
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.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.PackageManagerException;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.component.ParsedActivityUtils;
import com.android.server.pm.pkg.component.ParsedPermissionUtils;
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 3b926c266b16..67b91d2646d9 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
@@ -18,12 +18,11 @@ package com.android.server.pm.parsing
import android.annotation.RawRes
import android.content.Context
-import com.android.server.pm.pkg.parsing.ParsingPackage
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import android.content.pm.parsing.result.ParseResult
import android.platform.test.annotations.Presubmit
import androidx.test.InstrumentationRegistry
-import com.android.server.pm.parsing.pkg.ParsedPackage
+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
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 f376e7397042..6cd71237efa2 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.ParsedPackage;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
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 9248da65e330..27fd781584f2 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.ParsedPackage;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
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 23a2c20c8fa2..b13d6de55cf6 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.ParsedPackage;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
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 2060caaac2b5..fa69f844c33a 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.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
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 b3ad8616b112..856013a96017 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.ParsedPackage;
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
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 558c0e8b4736..ae5ea21aec4e 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.ParsedPackage;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
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 7a2ac75ab0d6..e126ffcab5ff 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.ParsedPackage;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
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 c4b8e6f445c5..d0b0cf894340 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,11 +28,11 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+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.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
import org.junit.Assume;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
index 33fc261d764f..d60c457a10b3 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
@@ -18,7 +18,7 @@ package com.android.server.pm.parsing.library;
import static org.junit.Assert.assertEquals;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import java.util.function.Supplier;
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 89182333cb16..c141c0337540 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.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
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 3e9ec0e3e4e5..a58604b81e06 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.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
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 766ab94e8587..9341e9d96335 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
@@ -21,9 +21,9 @@ import android.content.pm.ApplicationInfo
import android.os.Build
import android.os.PatternMatcher
import android.util.ArraySet
+import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
import com.android.server.SystemConfig
import com.android.server.compat.PlatformCompat
-import com.android.server.pm.parsing.pkg.AndroidPackageInternal
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.component.ParsedActivityImpl
import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
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 9fbf86e36df4..a737b9097b53 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
@@ -28,9 +28,8 @@ import android.util.ArraySet
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.server.pm.Computer
-import com.android.server.pm.parsing.pkg.AndroidPackageInternal
-import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
import com.android.server.pm.pkg.component.ParsedActivityImpl
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 47d9196b502b..f38df22af630 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
@@ -29,7 +29,7 @@ import android.os.PatternMatcher
import android.os.Process
import android.util.ArraySet
import android.util.SparseArray
-import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
import com.android.server.pm.pkg.component.ParsedActivityImpl
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 98d780143ff7..874e0d2bbc9a 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
@@ -36,9 +36,8 @@ import android.os.Process
import android.util.ArraySet
import android.util.SparseArray
import android.util.Xml
+import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
import com.android.server.pm.Computer
-import com.android.server.pm.parsing.pkg.AndroidPackageInternal
-import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
import com.android.server.pm.pkg.component.ParsedActivityImpl
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 4a211dfeb91e..3207e6c2a411 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
@@ -24,7 +24,7 @@ import android.os.Build
import android.os.Process
import android.util.ArraySet
import android.util.SparseArray
-import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
import com.android.server.pm.pkg.component.ParsedActivityImpl
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 d54d608e48c2..a90b7d5ec7da 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
@@ -26,8 +26,7 @@ import android.os.PatternMatcher
import android.os.Process
import android.util.ArraySet
import android.util.SparseArray
-import com.android.server.pm.parsing.pkg.AndroidPackageInternal
-import com.android.server.pm.pkg.AndroidPackage
+import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
import com.android.server.pm.pkg.component.ParsedActivityImpl
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/BaseModeRefreshRateVoteTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/BaseModeRefreshRateVoteTest.kt
new file mode 100644
index 000000000000..3f72364005ab
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/BaseModeRefreshRateVoteTest.kt
@@ -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.display.mode
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.server.display.mode.DisplayModeDirector.VoteSummary
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+
+private const val BASE_REFRESH_RATE = 60f
+private const val OTHER_BASE_REFRESH_RATE = 90f
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BaseModeRefreshRateVoteTest {
+
+ private lateinit var baseModeVote: BaseModeRefreshRateVote
+
+ @Before
+ fun setUp() {
+ baseModeVote = BaseModeRefreshRateVote(BASE_REFRESH_RATE)
+ }
+
+ @Test
+ fun `updates summary with base mode refresh rate if not set`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+
+ baseModeVote.updateSummary(summary)
+
+ assertThat(summary.appRequestBaseModeRefreshRate).isEqualTo(BASE_REFRESH_RATE)
+ }
+
+ @Test
+ fun `keeps summary base mode refresh rate if set`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.appRequestBaseModeRefreshRate = OTHER_BASE_REFRESH_RATE
+
+ baseModeVote.updateSummary(summary)
+
+ assertThat(summary.appRequestBaseModeRefreshRate).isEqualTo(OTHER_BASE_REFRESH_RATE)
+ }
+
+ @Test
+ fun `keeps summary with base mode refresh rate if vote refresh rate is negative`() {
+ val invalidBaseModeVote = BaseModeRefreshRateVote(-10f)
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+
+ invalidBaseModeVote.updateSummary(summary)
+
+ assertThat(summary.appRequestBaseModeRefreshRate).isZero()
+ }
+} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/CombinedVoteTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/CombinedVoteTest.kt
new file mode 100644
index 000000000000..7f8da88ca996
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/CombinedVoteTest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.server.display.mode.DisplayModeDirector.VoteSummary
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.junit.MockitoJUnit
+
+
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CombinedVoteTest {
+ private lateinit var combinedVote: CombinedVote
+
+ @get:Rule
+ val mockitoRule = MockitoJUnit.rule()
+
+ private val mockVote1 = mock<Vote>()
+ private val mockVote2 = mock<Vote>()
+
+ @Before
+ fun setUp() {
+ combinedVote = CombinedVote(listOf(mockVote1, mockVote2))
+ }
+
+ @Test
+ fun `delegates update to children`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+
+ combinedVote.updateSummary(summary)
+
+ verify(mockVote1).updateSummary(summary)
+ verify(mockVote2).updateSummary(summary)
+ }
+} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisableRefreshRateSwitchingVoteTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/DisableRefreshRateSwitchingVoteTest.kt
new file mode 100644
index 000000000000..c624325d773c
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisableRefreshRateSwitchingVoteTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode
+
+import androidx.test.filters.SmallTest
+import com.android.server.display.mode.DisplayModeDirector.VoteSummary
+import com.google.common.truth.Truth.assertThat
+import com.google.testing.junit.testparameterinjector.TestParameter
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(TestParameterInjector::class)
+class DisableRefreshRateSwitchingVoteTest {
+
+ @Test
+ fun `disabled refresh rate switching is not changed`(
+ @TestParameter voteDisableSwitching: Boolean
+ ) {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.disableRefreshRateSwitching = true
+ val vote = DisableRefreshRateSwitchingVote(voteDisableSwitching)
+
+ vote.updateSummary(summary)
+
+ assertThat(summary.disableRefreshRateSwitching).isTrue()
+ }
+
+ @Test
+ fun `disables refresh rate switching if requested`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ val vote = DisableRefreshRateSwitchingVote(true)
+
+ vote.updateSummary(summary)
+
+ assertThat(summary.disableRefreshRateSwitching).isTrue()
+ }
+
+ @Test
+ fun `does not disable refresh rate switching if not requested`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ val vote = DisableRefreshRateSwitchingVote(false)
+
+ vote.updateSummary(summary)
+
+ assertThat(summary.disableRefreshRateSwitching).isFalse()
+ }
+} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index 6798a2da4c54..d0859232778d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -28,7 +28,6 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_R
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.server.display.mode.Vote.INVALID_SIZE;
import static com.google.common.truth.Truth.assertThat;
@@ -1193,7 +1192,9 @@ public class DisplayModeDirectorTest {
assertVoteForPhysicalRefreshRate(vote, 90 /*fps*/);
vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
assertThat(vote).isNotNull();
- assertThat(vote.disableRefreshRateSwitching).isTrue();
+ assertThat(vote).isInstanceOf(DisableRefreshRateSwitchingVote.class);
+ DisableRefreshRateSwitchingVote disableVote = (DisableRefreshRateSwitchingVote) vote;
+ assertThat(disableVote.mDisableRefreshRateSwitching).isTrue();
}
@Test
@@ -1272,7 +1273,9 @@ public class DisplayModeDirectorTest {
assertVoteForPhysicalRefreshRate(vote, 90 /*fps*/);
vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
assertThat(vote).isNotNull();
- assertThat(vote.disableRefreshRateSwitching).isTrue();
+ assertThat(vote).isInstanceOf(DisableRefreshRateSwitchingVote.class);
+ DisableRefreshRateSwitchingVote disableVote = (DisableRefreshRateSwitchingVote) vote;
+ assertThat(disableVote.mDisableRefreshRateSwitching).isTrue();
// We expect DisplayModeDirector to act on BrightnessInfo.adjustedBrightness; set only this
// parameter to the necessary threshold
@@ -1341,7 +1344,9 @@ public class DisplayModeDirectorTest {
assertVoteForPhysicalRefreshRate(vote, 60 /*fps*/);
vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
assertThat(vote).isNotNull();
- assertThat(vote.disableRefreshRateSwitching).isTrue();
+ assertThat(vote).isInstanceOf(DisableRefreshRateSwitchingVote.class);
+ DisableRefreshRateSwitchingVote disableVote = (DisableRefreshRateSwitchingVote) vote;
+ assertThat(disableVote.mDisableRefreshRateSwitching).isTrue();
}
@Test
@@ -1424,7 +1429,9 @@ public class DisplayModeDirectorTest {
assertVoteForPhysicalRefreshRate(vote, 90 /*fps*/);
vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
assertThat(vote).isNotNull();
- assertThat(vote.disableRefreshRateSwitching).isTrue();
+ assertThat(vote).isInstanceOf(DisableRefreshRateSwitchingVote.class);
+ DisableRefreshRateSwitchingVote disableVote = (DisableRefreshRateSwitchingVote) vote;
+ assertThat(disableVote.mDisableRefreshRateSwitching).isTrue();
// Set critical and check new refresh rate
Temperature temp = getSkinTemp(Temperature.THROTTLING_CRITICAL);
@@ -1436,7 +1443,9 @@ public class DisplayModeDirectorTest {
assertVoteForPhysicalRefreshRate(vote, 60 /*fps*/);
vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
assertThat(vote).isNotNull();
- assertThat(vote.disableRefreshRateSwitching).isTrue();
+ assertThat(vote).isInstanceOf(DisableRefreshRateSwitchingVote.class);
+ disableVote = (DisableRefreshRateSwitchingVote) vote;
+ assertThat(disableVote.mDisableRefreshRateSwitching).isTrue();
}
@Test
@@ -1519,7 +1528,9 @@ public class DisplayModeDirectorTest {
assertVoteForPhysicalRefreshRate(vote, 90 /*fps*/);
vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
assertThat(vote).isNotNull();
- assertThat(vote.disableRefreshRateSwitching).isTrue();
+ assertThat(vote).isInstanceOf(DisableRefreshRateSwitchingVote.class);
+ DisableRefreshRateSwitchingVote disableVote = (DisableRefreshRateSwitchingVote) vote;
+ assertThat(disableVote.mDisableRefreshRateSwitching).isTrue();
// Set critical and check new refresh rate
Temperature temp = getSkinTemp(Temperature.THROTTLING_CRITICAL);
@@ -1531,7 +1542,9 @@ public class DisplayModeDirectorTest {
assertVoteForPhysicalRefreshRate(vote, 60 /*fps*/);
vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
assertThat(vote).isNotNull();
- assertThat(vote.disableRefreshRateSwitching).isTrue();
+ assertThat(vote).isInstanceOf(DisableRefreshRateSwitchingVote.class);
+ disableVote = (DisableRefreshRateSwitchingVote) vote;
+ assertThat(disableVote.mDisableRefreshRateSwitching).isTrue();
}
@Test
@@ -1877,61 +1890,43 @@ public class DisplayModeDirectorTest {
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 60, 0, 0);
- Vote appRequestRefreshRate =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
- assertNotNull(appRequestRefreshRate);
- assertThat(appRequestRefreshRate.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRate.refreshRateRanges.physical.max).isPositiveInfinity();
- assertThat(appRequestRefreshRate.refreshRateRanges.render.min).isZero();
- assertThat(appRequestRefreshRate.refreshRateRanges.render.max).isPositiveInfinity();
- assertThat(appRequestRefreshRate.disableRefreshRateSwitching).isFalse();
- assertThat(appRequestRefreshRate.appRequestBaseModeRefreshRate)
- .isWithin(FLOAT_TOLERANCE).of(60);
- assertThat(appRequestRefreshRate.height).isEqualTo(INVALID_SIZE);
- assertThat(appRequestRefreshRate.width).isEqualTo(INVALID_SIZE);
-
- Vote appRequestSize = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
- assertNotNull(appRequestSize);
- assertThat(appRequestSize.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestSize.refreshRateRanges.physical.max).isPositiveInfinity();
- assertThat(appRequestSize.refreshRateRanges.render.min).isZero();
- assertThat(appRequestSize.refreshRateRanges.render.max).isPositiveInfinity();
- assertThat(appRequestSize.disableRefreshRateSwitching).isFalse();
- assertThat(appRequestSize.appRequestBaseModeRefreshRate).isZero();
- assertThat(appRequestSize.height).isEqualTo(1000);
- assertThat(appRequestSize.width).isEqualTo(1000);
-
- Vote appRequestRefreshRateRange =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
- assertNull(appRequestRefreshRateRange);
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(BaseModeRefreshRateVote.class);
+ BaseModeRefreshRateVote baseModeVote = (BaseModeRefreshRateVote) vote;
+ assertThat(baseModeVote.mAppRequestBaseModeRefreshRate).isWithin(FLOAT_TOLERANCE).of(60);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(SizeVote.class);
+ SizeVote sizeVote = (SizeVote) vote;
+ assertThat(sizeVote.mHeight).isEqualTo(1000);
+ assertThat(sizeVote.mWidth).isEqualTo(1000);
+ assertThat(sizeVote.mMinHeight).isEqualTo(1000);
+ assertThat(sizeVote.mMinWidth).isEqualTo(1000);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
+ assertNull(vote);
director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 90, 0, 0);
- appRequestRefreshRate =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
- assertNotNull(appRequestRefreshRate);
- assertThat(appRequestRefreshRate.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRate.refreshRateRanges.physical.max).isPositiveInfinity();
- assertThat(appRequestRefreshRate.refreshRateRanges.render.min).isZero();
- assertThat(appRequestRefreshRate.refreshRateRanges.render.max).isPositiveInfinity();
- assertThat(appRequestRefreshRate.disableRefreshRateSwitching).isFalse();
- assertThat(appRequestRefreshRate.appRequestBaseModeRefreshRate)
- .isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(appRequestRefreshRate.height).isEqualTo(INVALID_SIZE);
- assertThat(appRequestRefreshRate.width).isEqualTo(INVALID_SIZE);
-
- appRequestSize = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
- assertNotNull(appRequestSize);
- assertThat(appRequestSize.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestSize.refreshRateRanges.physical.max).isPositiveInfinity();
- assertThat(appRequestSize.refreshRateRanges.render.min).isZero();
- assertThat(appRequestSize.refreshRateRanges.render.max).isPositiveInfinity();
- assertThat(appRequestSize.height).isEqualTo(1000);
- assertThat(appRequestSize.width).isEqualTo(1000);
-
- appRequestRefreshRateRange =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
- assertNull(appRequestRefreshRateRange);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(BaseModeRefreshRateVote.class);
+ baseModeVote = (BaseModeRefreshRateVote) vote;
+ assertThat(baseModeVote.mAppRequestBaseModeRefreshRate).isWithin(FLOAT_TOLERANCE).of(90);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(SizeVote.class);
+ sizeVote = (SizeVote) vote;
+ assertThat(sizeVote.mHeight).isEqualTo(1000);
+ assertThat(sizeVote.mWidth).isEqualTo(1000);
+ assertThat(sizeVote.mMinHeight).isEqualTo(1000);
+ assertThat(sizeVote.mMinWidth).isEqualTo(1000);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
+ assertNull(vote);
}
@Test
@@ -1945,17 +1940,12 @@ public class DisplayModeDirectorTest {
Vote appRequestSize = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
assertNull(appRequestSize);
- Vote appRequestRefreshRateRange =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
- assertNotNull(appRequestRefreshRateRange);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isPositiveInfinity();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min)
- .isWithin(FLOAT_TOLERANCE).of(60);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max).isAtLeast(90);
- assertThat(appRequestRefreshRateRange.height).isEqualTo(INVALID_SIZE);
- assertThat(appRequestRefreshRateRange.width).isEqualTo(INVALID_SIZE);
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(RefreshRateVote.RenderVote.class);
+ RefreshRateVote.RenderVote renderVote = (RefreshRateVote.RenderVote) vote;
+ assertThat(renderVote.mMinRefreshRate).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(renderVote.mMaxRefreshRate).isAtLeast(90);
director.getAppRequestObserver().setAppRequest(DISPLAY_ID, -1, 90, 0);
appRequestRefreshRate =
@@ -1965,18 +1955,12 @@ public class DisplayModeDirectorTest {
appRequestSize = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
assertNull(appRequestSize);
- appRequestRefreshRateRange =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
- assertNotNull(appRequestRefreshRateRange);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isPositiveInfinity();
-
- assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min)
- .isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max).isAtLeast(90);
- assertThat(appRequestRefreshRateRange.height).isEqualTo(INVALID_SIZE);
- assertThat(appRequestRefreshRateRange.width).isEqualTo(INVALID_SIZE);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(RefreshRateVote.RenderVote.class);
+ renderVote = (RefreshRateVote.RenderVote) vote;
+ assertThat(renderVote.mMinRefreshRate).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(renderVote.mMaxRefreshRate).isAtLeast(90);
}
@Test
@@ -1990,18 +1974,12 @@ public class DisplayModeDirectorTest {
Vote appRequestSize = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
assertNull(appRequestSize);
- Vote appRequestRefreshRateRange =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
- assertNotNull(appRequestRefreshRateRange);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isPositiveInfinity();
-
- assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min).isZero();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max)
- .isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(appRequestRefreshRateRange.height).isEqualTo(INVALID_SIZE);
- assertThat(appRequestRefreshRateRange.width).isEqualTo(INVALID_SIZE);
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(RefreshRateVote.RenderVote.class);
+ RefreshRateVote.RenderVote renderVote = (RefreshRateVote.RenderVote) vote;
+ assertThat(renderVote.mMinRefreshRate).isZero();
+ assertThat(renderVote.mMaxRefreshRate).isWithin(FLOAT_TOLERANCE).of(90);
director.getAppRequestObserver().setAppRequest(DISPLAY_ID, -1, 0, 60);
appRequestRefreshRate =
@@ -2011,18 +1989,12 @@ public class DisplayModeDirectorTest {
appRequestSize = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
assertNull(appRequestSize);
- appRequestRefreshRateRange =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
- assertNotNull(appRequestRefreshRateRange);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isPositiveInfinity();
-
- assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min).isZero();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max)
- .isWithin(FLOAT_TOLERANCE).of(60);
- assertThat(appRequestRefreshRateRange.height).isEqualTo(INVALID_SIZE);
- assertThat(appRequestRefreshRateRange.width).isEqualTo(INVALID_SIZE);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(RefreshRateVote.RenderVote.class);
+ renderVote = (RefreshRateVote.RenderVote) vote;
+ assertThat(renderVote.mMinRefreshRate).isZero();
+ assertThat(renderVote.mMaxRefreshRate).isWithin(FLOAT_TOLERANCE).of(60);
}
@Test
@@ -2046,41 +2018,27 @@ public class DisplayModeDirectorTest {
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 60, 90, 90);
- Vote appRequestRefreshRate =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
- assertNotNull(appRequestRefreshRate);
- assertThat(appRequestRefreshRate.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRate.refreshRateRanges.physical.max).isPositiveInfinity();
- assertThat(appRequestRefreshRate.refreshRateRanges.render.min).isZero();
- assertThat(appRequestRefreshRate.refreshRateRanges.render.max).isPositiveInfinity();
- assertThat(appRequestRefreshRate.disableRefreshRateSwitching).isFalse();
- assertThat(appRequestRefreshRate.appRequestBaseModeRefreshRate)
- .isWithin(FLOAT_TOLERANCE).of(60);
- assertThat(appRequestRefreshRate.height).isEqualTo(INVALID_SIZE);
- assertThat(appRequestRefreshRate.width).isEqualTo(INVALID_SIZE);
-
- Vote appRequestSize =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
- assertNotNull(appRequestSize);
- assertThat(appRequestSize.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestSize.refreshRateRanges.physical.max).isPositiveInfinity();
- assertThat(appRequestSize.refreshRateRanges.render.min).isZero();
- assertThat(appRequestSize.refreshRateRanges.render.max).isPositiveInfinity();
- assertThat(appRequestSize.height).isEqualTo(1000);
- assertThat(appRequestSize.width).isEqualTo(1000);
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(BaseModeRefreshRateVote.class);
+ BaseModeRefreshRateVote baseModeVote = (BaseModeRefreshRateVote) vote;
+ assertThat(baseModeVote.mAppRequestBaseModeRefreshRate).isWithin(FLOAT_TOLERANCE).of(60);
- Vote appRequestRefreshRateRange =
- director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
- assertNotNull(appRequestRefreshRateRange);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isPositiveInfinity();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min)
- .isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max)
- .isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(appRequestRefreshRateRange.height).isEqualTo(INVALID_SIZE);
- assertThat(appRequestRefreshRateRange.width).isEqualTo(INVALID_SIZE);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(SizeVote.class);
+ SizeVote sizeVote = (SizeVote) vote;
+ assertThat(sizeVote.mHeight).isEqualTo(1000);
+ assertThat(sizeVote.mWidth).isEqualTo(1000);
+ assertThat(sizeVote.mMinHeight).isEqualTo(1000);
+ assertThat(sizeVote.mMinWidth).isEqualTo(1000);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
+ assertNotNull(vote);
+ assertThat(vote).isInstanceOf(RefreshRateVote.RenderVote.class);
+ RefreshRateVote.RenderVote renderVote = (RefreshRateVote.RenderVote) vote;
+ assertThat(renderVote.mMinRefreshRate).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(renderVote.mMaxRefreshRate).isWithin(FLOAT_TOLERANCE).of(90);
}
@Test
@@ -3150,8 +3108,7 @@ public class DisplayModeDirectorTest {
captor.getValue().onAuthenticationPossible(DISPLAY_ID, true);
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE);
- assertThat(vote.refreshRateRanges.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(vote.refreshRateRanges.physical.max).isWithin(FLOAT_TOLERANCE).of(90);
+ assertVoteForPhysicalRefreshRate(vote, 90);
}
@Test
@@ -3184,8 +3141,7 @@ public class DisplayModeDirectorTest {
captor.getValue().onRequestEnabled(DISPLAY_ID);
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_UDFPS);
- assertThat(vote.refreshRateRanges.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(vote.refreshRateRanges.physical.max).isWithin(FLOAT_TOLERANCE).of(90);
+ assertVoteForPhysicalRefreshRate(vote, 90);
}
@Test
@@ -3257,16 +3213,21 @@ public class DisplayModeDirectorTest {
private void assertVoteForPhysicalRefreshRate(Vote vote, float refreshRate) {
assertThat(vote).isNotNull();
- final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
- assertThat(vote.refreshRateRanges.physical).isEqualTo(expectedRange);
+ assertThat(vote).isInstanceOf(CombinedVote.class);
+ CombinedVote combinedVote = (CombinedVote) vote;
+ RefreshRateVote.PhysicalVote physicalVote =
+ (RefreshRateVote.PhysicalVote) combinedVote.mVotes.get(0);
+ assertThat(physicalVote.mMinRefreshRate).isWithin(FLOAT_TOLERANCE).of(refreshRate);
+ assertThat(physicalVote.mMaxRefreshRate).isWithin(FLOAT_TOLERANCE).of(refreshRate);
}
private void assertVoteForRenderFrameRateRange(
Vote vote, float frameRateLow, float frameRateHigh) {
assertThat(vote).isNotNull();
- final RefreshRateRange expectedRange =
- new RefreshRateRange(frameRateLow, frameRateHigh);
- assertThat(vote.refreshRateRanges.render).isEqualTo(expectedRange);
+ assertThat(vote).isInstanceOf(RefreshRateVote.RenderVote.class);
+ RefreshRateVote.RenderVote renderVote = (RefreshRateVote.RenderVote) vote;
+ assertThat(renderVote.mMinRefreshRate).isEqualTo(frameRateLow);
+ assertThat(renderVote.mMaxRefreshRate).isEqualTo(frameRateHigh);
}
public static class FakeDeviceConfig extends FakeDeviceConfigInterface {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/PhysicalVoteTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/PhysicalVoteTest.kt
new file mode 100644
index 000000000000..547008e2fe56
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/PhysicalVoteTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode
+
+import androidx.test.filters.SmallTest
+import com.android.server.display.mode.DisplayModeDirector.VoteSummary
+import com.google.common.truth.Truth.assertThat
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val MIN_REFRESH_RATE = 60f
+private const val MAX_REFRESH_RATE = 90f
+
+@SmallTest
+@RunWith(TestParameterInjector::class)
+class PhysicalVoteTest {
+ private lateinit var physicalVote: RefreshRateVote.PhysicalVote
+
+ @Before
+ fun setUp() {
+ physicalVote = RefreshRateVote.PhysicalVote(MIN_REFRESH_RATE, MAX_REFRESH_RATE)
+ }
+
+ @Test
+ fun `updates minPhysicalRefreshRate if summary has less`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.minPhysicalRefreshRate = 45f
+
+ physicalVote.updateSummary(summary)
+
+ assertThat(summary.minPhysicalRefreshRate).isEqualTo(MIN_REFRESH_RATE)
+ }
+
+ @Test
+ fun `does not update minPhysicalRefreshRate if summary has more`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.minPhysicalRefreshRate = 75f
+
+ physicalVote.updateSummary(summary)
+
+ assertThat(summary.minPhysicalRefreshRate).isEqualTo(75f)
+ }
+
+ @Test
+ fun `updates maxPhysicalRefreshRate if summary has more`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.maxPhysicalRefreshRate = 120f
+
+ physicalVote.updateSummary(summary)
+
+ assertThat(summary.maxPhysicalRefreshRate).isEqualTo(MAX_REFRESH_RATE)
+ }
+
+ @Test
+ fun `does not update maxPhysicalRefreshRate if summary has less`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.maxPhysicalRefreshRate = 75f
+
+ physicalVote.updateSummary(summary)
+
+ assertThat(summary.maxPhysicalRefreshRate).isEqualTo(75f)
+ }
+
+ @Test
+ fun `updates maxRenderFrameRate if summary has more`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.maxRenderFrameRate = 120f
+
+ physicalVote.updateSummary(summary)
+
+ assertThat(summary.maxRenderFrameRate).isEqualTo(MAX_REFRESH_RATE)
+ }
+
+ @Test
+ fun `does not update maxRenderFrameRate if summary has less`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.maxRenderFrameRate = 75f
+
+ physicalVote.updateSummary(summary)
+
+ assertThat(summary.maxRenderFrameRate).isEqualTo(75f)
+ }
+} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/RenderVoteTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/RenderVoteTest.kt
new file mode 100644
index 000000000000..868a89393d5f
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/RenderVoteTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode
+
+import androidx.test.filters.SmallTest
+import com.android.server.display.mode.DisplayModeDirector.VoteSummary
+import com.google.common.truth.Truth.assertThat
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val MIN_REFRESH_RATE = 60f
+private const val MAX_REFRESH_RATE = 90f
+
+@SmallTest
+@RunWith(TestParameterInjector::class)
+class RenderVoteTest {
+
+ private lateinit var renderVote: RefreshRateVote.RenderVote
+
+ @Before
+ fun setUp() {
+ renderVote = RefreshRateVote.RenderVote(MIN_REFRESH_RATE, MAX_REFRESH_RATE)
+ }
+
+ @Test
+ fun `updates minRenderFrameRate if summary has less`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.minRenderFrameRate = 45f
+
+ renderVote.updateSummary(summary)
+
+ assertThat(summary.minRenderFrameRate).isEqualTo(MIN_REFRESH_RATE)
+ }
+
+ @Test
+ fun `does not update minRenderFrameRate if summary has more`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.minRenderFrameRate = 75f
+
+ renderVote.updateSummary(summary)
+
+ assertThat(summary.minRenderFrameRate).isEqualTo(75f)
+ }
+
+ @Test
+ fun `updates maxRenderFrameRate if summary has more`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.maxRenderFrameRate = 120f
+
+ renderVote.updateSummary(summary)
+
+ assertThat(summary.maxRenderFrameRate).isEqualTo(MAX_REFRESH_RATE)
+ }
+
+ @Test
+ fun `does not update maxRenderFrameRate if summary has less`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.maxRenderFrameRate = 75f
+
+ renderVote.updateSummary(summary)
+
+ assertThat(summary.maxRenderFrameRate).isEqualTo(75f)
+ }
+
+ @Test
+ fun `updates minPhysicalRefreshRate if summary has less`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.minPhysicalRefreshRate = 45f
+
+ renderVote.updateSummary(summary)
+
+ assertThat(summary.minPhysicalRefreshRate).isEqualTo(MIN_REFRESH_RATE)
+ }
+
+ @Test
+ fun `does not update minPhysicalRefreshRate if summary has more`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.minPhysicalRefreshRate = 75f
+
+ renderVote.updateSummary(summary)
+
+ assertThat(summary.minPhysicalRefreshRate).isEqualTo(75f)
+ }
+} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SizeVoteTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SizeVoteTest.kt
new file mode 100644
index 000000000000..1c631b07a2ff
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SizeVoteTest.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.server.display.mode.DisplayModeDirector.VoteSummary
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+
+private const val WIDTH = 800
+private const val HEIGHT = 1600
+private const val MIN_WIDTH = 400
+private const val MIN_HEIGHT = 1200
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SizeVoteTest {
+ private lateinit var sizeVote: SizeVote
+
+ @Before
+ fun setUp() {
+ sizeVote = SizeVote(WIDTH, HEIGHT, MIN_WIDTH, MIN_HEIGHT)
+ }
+
+ @Test
+ fun `updates size if width and height not set and display resolution voting disabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ false)
+ summary.width = Vote.INVALID_SIZE
+ summary.height = Vote.INVALID_SIZE
+ summary.minWidth = 100
+ summary.minHeight = 200
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.width).isEqualTo(WIDTH)
+ assertThat(summary.height).isEqualTo(HEIGHT)
+ assertThat(summary.minWidth).isEqualTo(MIN_WIDTH)
+ assertThat(summary.minHeight).isEqualTo(MIN_HEIGHT)
+ }
+
+ @Test
+ fun `does not update size if width set and display resolution voting disabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ false)
+ summary.width = 150
+ summary.height = Vote.INVALID_SIZE
+ summary.minWidth = 100
+ summary.minHeight = 200
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.width).isEqualTo(150)
+ assertThat(summary.height).isEqualTo(Vote.INVALID_SIZE)
+ assertThat(summary.minWidth).isEqualTo(100)
+ assertThat(summary.minHeight).isEqualTo(200)
+ }
+
+ @Test
+ fun `does not update size if height set and display resolution voting disabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ false)
+ summary.width = Vote.INVALID_SIZE
+ summary.height = 250
+ summary.minWidth = 100
+ summary.minHeight = 200
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.width).isEqualTo(Vote.INVALID_SIZE)
+ assertThat(summary.height).isEqualTo(250)
+ assertThat(summary.minWidth).isEqualTo(100)
+ assertThat(summary.minHeight).isEqualTo(200)
+ }
+
+ @Test
+ fun `updates width if summary has more and display resolution voting enabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.width = 850
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.width).isEqualTo(WIDTH)
+ }
+
+ @Test
+ fun `does not update width if summary has less and display resolution voting enabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.width = 750
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.width).isEqualTo(750)
+ }
+
+ @Test
+ fun `updates height if summary has more and display resolution voting enabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.height = 1650
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.height).isEqualTo(HEIGHT)
+ }
+
+ @Test
+ fun `does not update height if summary has less and display resolution voting enabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.height = 1550
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.height).isEqualTo(1550)
+ }
+
+ @Test
+ fun `updates minWidth if summary has less and display resolution voting enabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.width = 150
+ summary.minWidth = 350
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.minWidth).isEqualTo(MIN_WIDTH)
+ }
+
+ @Test
+ fun `does not update minWidth if summary has more and display resolution voting enabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.width = 150
+ summary.minWidth = 450
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.minWidth).isEqualTo(450)
+ }
+
+ @Test
+ fun `updates minHeight if summary has less and display resolution voting enabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.width = 150
+ summary.minHeight = 1150
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.minHeight).isEqualTo(MIN_HEIGHT)
+ }
+
+ @Test
+ fun `does not update minHeight if summary has more and display resolution voting enabled`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.width = 150
+ summary.minHeight = 1250
+
+ sizeVote.updateSummary(summary)
+
+ assertThat(summary.minHeight).isEqualTo(1250)
+ }
+} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
index 9ab6ee5bd230..f6774017c523 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
@@ -17,6 +17,8 @@
package com.android.server.display.mode;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -102,17 +104,21 @@ public class SkinThermalStatusObserverTest {
SparseArray<Vote> displayVotes = mStorage.getVotes(DISPLAY_ID);
assertEquals(1, displayVotes.size());
- Vote vote = displayVotes.get(
- Vote.PRIORITY_SKIN_TEMPERATURE);
- assertEquals(0, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
- assertEquals(60, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
+ Vote vote = displayVotes.get(Vote.PRIORITY_SKIN_TEMPERATURE);
+
+ assertThat(vote).isInstanceOf(RefreshRateVote.RenderVote.class);
+ RefreshRateVote.RenderVote renderVote = (RefreshRateVote.RenderVote) vote;
+ assertEquals(0, renderVote.mMinRefreshRate, FLOAT_TOLERANCE);
+ assertEquals(60, renderVote.mMaxRefreshRate, FLOAT_TOLERANCE);
SparseArray<Vote> otherDisplayVotes = mStorage.getVotes(DISPLAY_ID_OTHER);
assertEquals(1, otherDisplayVotes.size());
vote = otherDisplayVotes.get(Vote.PRIORITY_SKIN_TEMPERATURE);
- assertEquals(0, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
- assertEquals(60, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
+ assertThat(vote).isInstanceOf(RefreshRateVote.RenderVote.class);
+ renderVote = (RefreshRateVote.RenderVote) vote;
+ assertEquals(0, renderVote.mMinRefreshRate, FLOAT_TOLERANCE);
+ assertEquals(60, renderVote.mMaxRefreshRate, FLOAT_TOLERANCE);
}
@Test
@@ -167,8 +173,10 @@ public class SkinThermalStatusObserverTest {
SparseArray<Vote> displayVotes = mStorage.getVotes(DISPLAY_ID);
assertEquals(1, displayVotes.size());
Vote vote = displayVotes.get(Vote.PRIORITY_SKIN_TEMPERATURE);
- assertEquals(90, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
- assertEquals(120, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
+ assertThat(vote).isInstanceOf(RefreshRateVote.RenderVote.class);
+ RefreshRateVote.RenderVote renderVote = (RefreshRateVote.RenderVote) vote;
+ assertEquals(90, renderVote.mMinRefreshRate, FLOAT_TOLERANCE);
+ assertEquals(120, renderVote.mMaxRefreshRate, FLOAT_TOLERANCE);
assertEquals(0, mStorage.getVotes(DISPLAY_ID_OTHER).size());
}
@@ -188,8 +196,10 @@ public class SkinThermalStatusObserverTest {
SparseArray<Vote> displayVotes = mStorage.getVotes(DISPLAY_ID_ADDED);
Vote vote = displayVotes.get(Vote.PRIORITY_SKIN_TEMPERATURE);
- assertEquals(0, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
- assertEquals(60, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
+ assertThat(vote).isInstanceOf(RefreshRateVote.RenderVote.class);
+ RefreshRateVote.RenderVote renderVote = (RefreshRateVote.RenderVote) vote;
+ assertEquals(0, renderVote.mMinRefreshRate, FLOAT_TOLERANCE);
+ assertEquals(60, renderVote.mMaxRefreshRate, FLOAT_TOLERANCE);
}
@Test
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SupportedModesVoteTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SupportedModesVoteTest.kt
new file mode 100644
index 000000000000..cc8800395d1e
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SupportedModesVoteTest.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.server.display.mode
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.server.display.mode.DisplayModeDirector.VoteSummary
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SupportedModesVoteTest {
+ private val supportedModes = listOf(
+ SupportedModesVote.SupportedMode(60f, 90f ),
+ SupportedModesVote.SupportedMode(120f, 240f )
+ )
+
+ private val otherMode = SupportedModesVote.SupportedMode(120f, 120f )
+
+ private lateinit var supportedModesVote: SupportedModesVote
+
+ @Before
+ fun setUp() {
+ supportedModesVote = SupportedModesVote(supportedModes)
+ }
+
+ @Test
+ fun `adds supported modes if supportedModes in summary is null`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+
+ supportedModesVote.updateSummary(summary)
+
+ assertThat(summary.supportedModes).containsExactlyElementsIn(supportedModes)
+ }
+
+ @Test
+ fun `does not add supported modes if summary has empty list of modes`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.supportedModes = ArrayList()
+
+ supportedModesVote.updateSummary(summary)
+
+ assertThat(summary.supportedModes).isEmpty()
+ }
+
+ @Test
+ fun `filters out modes that does not match vote`() {
+ val summary = VoteSummary(/* isDisplayResolutionRangeVotingEnabled= */ true)
+ summary.supportedModes = ArrayList(listOf(otherMode, supportedModes[0]))
+
+ supportedModesVote.updateSummary(summary)
+
+ assertThat(summary.supportedModes).containsExactly(supportedModes[0])
+ }
+} \ No newline at end of file
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 be33b1b6f34f..46806f334a27 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -55,6 +55,8 @@ 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.ParsedPackage
+import com.android.internal.pm.pkg.parsing.ParsingPackage
import com.android.server.LocalManagerRegistry
import com.android.server.LocalServices
import com.android.server.LockGuard
@@ -66,10 +68,8 @@ 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.parsing.pkg.ParsedPackage
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.parsing.ParsingPackage
import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.resolution.ComponentResolver
import com.android.server.pm.snapshot.PackageDataSnapshot
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 b8f726b393cc..e685c3fa9fa4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -25,13 +25,13 @@ import android.os.storage.StorageManager
import android.os.UserHandle
import android.util.ArrayMap
import android.util.PackageUtils
+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.pm.parsing.pkg.ParsedPackage
import com.android.server.testutils.any
import com.android.server.testutils.eq
import com.android.server.testutils.mock
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 3a3ab84b1c89..dd687fd4286c 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.ParsedPackage;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.PackageState;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
index 57b12251c207..d70a4fd555ec 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
@@ -60,7 +60,8 @@ public class UserManagerServiceUserPropertiesTest {
.setShowInLauncher(21)
.setStartWithParent(false)
.setShowInSettings(45)
- .setHideInSettingsInQuietMode(false)
+ .setShowInSharingSurfaces(78)
+ .setShowInQuietMode(12)
.setInheritDevicePolicy(67)
.setUseParentsContacts(false)
.setCrossProfileIntentFilterAccessControl(10)
@@ -74,7 +75,8 @@ public class UserManagerServiceUserPropertiesTest {
final UserProperties actualProps = new UserProperties(defaultProps);
actualProps.setShowInLauncher(14);
actualProps.setShowInSettings(32);
- actualProps.setHideInSettingsInQuietMode(true);
+ actualProps.setShowInSharingSurfaces(46);
+ actualProps.setShowInQuietMode(27);
actualProps.setInheritDevicePolicy(51);
actualProps.setUseParentsContacts(true);
actualProps.setCrossProfileIntentFilterAccessControl(20);
@@ -236,8 +238,10 @@ public class UserManagerServiceUserPropertiesTest {
assertThat(expected.getShowInLauncher()).isEqualTo(actual.getShowInLauncher());
assertThat(expected.getStartWithParent()).isEqualTo(actual.getStartWithParent());
assertThat(expected.getShowInSettings()).isEqualTo(actual.getShowInSettings());
- assertThat(expected.getHideInSettingsInQuietMode())
- .isEqualTo(actual.getHideInSettingsInQuietMode());
+ assertThat(expected.getShowInSharingSurfaces()).isEqualTo(
+ actual.getShowInSharingSurfaces());
+ assertThat(expected.getShowInQuietMode())
+ .isEqualTo(actual.getShowInQuietMode());
assertThat(expected.getInheritDevicePolicy()).isEqualTo(actual.getInheritDevicePolicy());
assertThat(expected.getUseParentsContacts()).isEqualTo(actual.getUseParentsContacts());
assertThat(expected.getCrossProfileIntentFilterAccessControl())
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index 48eb5c64f3d1..77f693917574 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -29,6 +29,7 @@ import static com.android.server.pm.UserTypeDetails.UNLIMITED_NUMBER_OF_USERS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
@@ -91,7 +92,8 @@ public class UserManagerServiceUserTypeTest {
.setCredentialShareableWithParent(false)
.setAuthAlwaysRequiredToDisableQuietMode(true)
.setShowInSettings(900)
- .setHideInSettingsInQuietMode(true)
+ .setShowInSharingSurfaces(20)
+ .setShowInQuietMode(30)
.setInheritDevicePolicy(340)
.setDeleteAppWithParent(true)
.setAlwaysVisible(true);
@@ -107,9 +109,9 @@ public class UserManagerServiceUserTypeTest {
.setIconBadge(28)
.setBadgePlain(29)
.setBadgeNoBackground(30)
- .setLabel(31)
.setMaxAllowedPerParent(32)
.setStatusBarIcon(33)
+ .setLabels(34, 35, 36)
.setDefaultRestrictions(restrictions)
.setDefaultSystemSettings(systemSettings)
.setDefaultSecureSettings(secureSettings)
@@ -124,9 +126,11 @@ public class UserManagerServiceUserTypeTest {
assertEquals(28, type.getIconBadge());
assertEquals(29, type.getBadgePlain());
assertEquals(30, type.getBadgeNoBackground());
- assertEquals(31, type.getLabel());
assertEquals(32, type.getMaxAllowedPerParent());
assertEquals(33, type.getStatusBarIcon());
+ assertEquals(34, type.getLabel(0));
+ assertEquals(35, type.getLabel(1));
+ assertEquals(36, type.getLabel(2));
assertTrue(UserRestrictionsUtils.areEqual(restrictions, type.getDefaultRestrictions()));
assertNotSame(restrictions, type.getDefaultRestrictions());
@@ -164,7 +168,9 @@ public class UserManagerServiceUserTypeTest {
assertTrue(type.getDefaultUserPropertiesReference()
.isAuthAlwaysRequiredToDisableQuietMode());
assertEquals(900, type.getDefaultUserPropertiesReference().getShowInSettings());
- assertTrue(type.getDefaultUserPropertiesReference().getHideInSettingsInQuietMode());
+ assertEquals(20, type.getDefaultUserPropertiesReference().getShowInSharingSurfaces());
+ assertEquals(30,
+ type.getDefaultUserPropertiesReference().getShowInQuietMode());
assertEquals(340, type.getDefaultUserPropertiesReference()
.getInheritDevicePolicy());
assertTrue(type.getDefaultUserPropertiesReference().getDeleteAppWithParent());
@@ -203,7 +209,7 @@ public class UserManagerServiceUserTypeTest {
assertEquals(Resources.ID_NULL, type.getStatusBarIcon());
assertEquals(Resources.ID_NULL, type.getBadgeLabel(0));
assertEquals(Resources.ID_NULL, type.getBadgeColor(0));
- assertEquals(Resources.ID_NULL, type.getLabel());
+ assertEquals(Resources.ID_NULL, type.getLabel(0));
assertTrue(type.getDefaultRestrictions().isEmpty());
assertTrue(type.getDefaultSystemSettings().isEmpty());
assertTrue(type.getDefaultSecureSettings().isEmpty());
@@ -222,7 +228,9 @@ public class UserManagerServiceUserTypeTest {
assertFalse(props.isCredentialShareableWithParent());
assertFalse(props.getDeleteAppWithParent());
assertFalse(props.getAlwaysVisible());
- assertFalse(props.getHideInSettingsInQuietMode());
+ assertEquals(UserProperties.SHOW_IN_LAUNCHER_SEPARATE, props.getShowInSharingSurfaces());
+ assertEquals(UserProperties.SHOW_IN_QUIET_MODE_PAUSED,
+ props.getShowInQuietMode());
assertFalse(type.hasBadge());
}
@@ -311,8 +319,9 @@ public class UserManagerServiceUserTypeTest {
.setCredentialShareableWithParent(true)
.setAuthAlwaysRequiredToDisableQuietMode(false)
.setShowInSettings(20)
- .setHideInSettingsInQuietMode(false)
.setInheritDevicePolicy(21)
+ .setShowInSharingSurfaces(22)
+ .setShowInQuietMode(24)
.setDeleteAppWithParent(true)
.setAlwaysVisible(false);
@@ -354,9 +363,11 @@ public class UserManagerServiceUserTypeTest {
assertFalse(aospType.getDefaultUserPropertiesReference()
.isAuthAlwaysRequiredToDisableQuietMode());
assertEquals(20, aospType.getDefaultUserPropertiesReference().getShowInSettings());
- assertFalse(aospType.getDefaultUserPropertiesReference().getHideInSettingsInQuietMode());
assertEquals(21, aospType.getDefaultUserPropertiesReference()
.getInheritDevicePolicy());
+ assertEquals(22, aospType.getDefaultUserPropertiesReference().getShowInSharingSurfaces());
+ assertEquals(24,
+ aospType.getDefaultUserPropertiesReference().getShowInQuietMode());
assertTrue(aospType.getDefaultUserPropertiesReference().getDeleteAppWithParent());
assertFalse(aospType.getDefaultUserPropertiesReference().getAlwaysVisible());
@@ -403,7 +414,10 @@ public class UserManagerServiceUserTypeTest {
assertTrue(aospType.getDefaultUserPropertiesReference()
.isAuthAlwaysRequiredToDisableQuietMode());
assertEquals(23, aospType.getDefaultUserPropertiesReference().getShowInSettings());
- assertTrue(aospType.getDefaultUserPropertiesReference().getHideInSettingsInQuietMode());
+ assertEquals(22,
+ aospType.getDefaultUserPropertiesReference().getShowInSharingSurfaces());
+ assertEquals(24,
+ aospType.getDefaultUserPropertiesReference().getShowInQuietMode());
assertEquals(450, aospType.getDefaultUserPropertiesReference()
.getInheritDevicePolicy());
assertFalse(aospType.getDefaultUserPropertiesReference().getDeleteAppWithParent());
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 2b6d8eda6bb0..c7d80edc9c2d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -343,6 +343,8 @@ public final class UserManagerTest {
assertThat(mainUserId).isEqualTo(parentProfileInfo.id);
removeUser(userInfo.id);
assertThat(mUserManager.getProfileParent(mainUserId)).isNull();
+ assertThat(mUserManager.getProfileLabel()).isEqualTo(
+ Resources.getSystem().getString(userTypeDetails.getLabel(0)));
}
@MediumTest
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 a8e3c7e4ef6d..8464969cd0f3 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.ParsedPackage;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.After;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index b2843d82a08a..1bfd43ff60ef 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -37,10 +37,10 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.servicestests.R;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.PackageManagerException;
import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Assert;
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 ad9f920f029d..0f87202f8939 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,10 +29,10 @@ import android.util.SparseArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+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.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
import dalvik.system.DelegateLastClassLoader;
import dalvik.system.DexClassLoader;
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index ebe45a6fa1e8..d00060564e74 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server.webkit;
+import static android.webkit.Flags.updateServiceV2;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -25,6 +27,9 @@ import android.content.pm.PackageInfo;
import android.content.pm.Signature;
import android.os.Build;
import android.os.Bundle;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Base64;
import android.webkit.UserPackage;
@@ -35,6 +40,7 @@ import android.webkit.WebViewProviderResponse;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
@@ -55,11 +61,14 @@ import java.util.concurrent.CountDownLatch;
public class WebViewUpdateServiceTest {
private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName();
- private WebViewUpdateServiceImpl mWebViewUpdateServiceImpl;
+ private WebViewUpdateServiceInterface mWebViewUpdateServiceImpl;
private TestSystemImpl mTestSystemImpl;
private static final String WEBVIEW_LIBRARY_FLAG = "com.android.webview.WebViewLibrary";
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
/**
* Creates a new instance.
*/
@@ -92,8 +101,13 @@ public class WebViewUpdateServiceTest {
TestSystemImpl testing = new TestSystemImpl(packages, numRelros, isDebuggable,
multiProcessDefault);
mTestSystemImpl = Mockito.spy(testing);
- mWebViewUpdateServiceImpl =
- new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl);
+ if (updateServiceV2()) {
+ mWebViewUpdateServiceImpl =
+ new WebViewUpdateServiceImpl2(null /*Context*/, mTestSystemImpl);
+ } else {
+ mWebViewUpdateServiceImpl =
+ new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl);
+ }
}
private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) {
@@ -1310,11 +1324,13 @@ public class WebViewUpdateServiceTest {
}
@Test
+ @RequiresFlagsDisabled("android.webkit.update_service_v2")
public void testMultiProcessEnabledByDefault() {
testMultiProcessByDefault(true /* enabledByDefault */);
}
@Test
+ @RequiresFlagsDisabled("android.webkit.update_service_v2")
public void testMultiProcessDisabledByDefault() {
testMultiProcessByDefault(false /* enabledByDefault */);
}
@@ -1344,6 +1360,7 @@ public class WebViewUpdateServiceTest {
}
@Test
+ @RequiresFlagsDisabled("android.webkit.update_service_v2")
public void testMultiProcessEnabledByDefaultWithSettingsValue() {
testMultiProcessByDefaultWithSettingsValue(
true /* enabledByDefault */, Integer.MIN_VALUE, false /* expectEnabled */);
@@ -1356,6 +1373,7 @@ public class WebViewUpdateServiceTest {
}
@Test
+ @RequiresFlagsDisabled("android.webkit.update_service_v2")
public void testMultiProcessDisabledByDefaultWithSettingsValue() {
testMultiProcessByDefaultWithSettingsValue(
false /* enabledByDefault */, Integer.MIN_VALUE, false /* expectEnabled */);
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 b45dcd4d5403..09ffe71a6758 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -241,7 +241,6 @@ import androidx.test.InstrumentationRegistry;
import com.android.internal.R;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.Flag;
import com.android.internal.config.sysui.TestableFlagResolver;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.InstanceIdSequenceFake;
@@ -5296,7 +5295,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
new Intent(Intent.ACTION_LOCALE_CHANGED));
verify(mZenModeHelper, times(1)).updateDefaultZenRules(
- anyInt(), anyBoolean());
+ anyInt());
}
@Test
@@ -8752,7 +8751,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// verify that zen mode helper gets passed in a package name of "android"
verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString(),
- anyInt(), eq(true)); // system call counts as "is system or system ui"
+ anyInt(), eq(ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI)); // system call
}
@Test
@@ -8774,7 +8773,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// verify that zen mode helper gets passed in a package name of "android"
verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString(),
- anyInt(), eq(true)); // system call counts as "system or system ui"
+ anyInt(), eq(ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI)); // system call
}
@Test
@@ -8795,7 +8794,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// verify that zen mode helper gets passed in the package name from the arg, not the owner
verify(mockZenModeHelper).addAutomaticZenRule(
eq("another.package"), eq(rule), anyString(), anyInt(),
- eq(false)); // doesn't count as a system/systemui call
+ eq(ZenModeHelper.FROM_APP)); // doesn't count as a system/systemui call
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
index 8f30f413d4d0..6976ec3b0465 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
@@ -82,7 +82,7 @@ public class TestableNotificationManagerService extends NotificationManagerServi
}
@Override
- protected boolean isCallerIsSystemOrSystemUi() {
+ protected boolean isCallerSystemOrSystemUi() {
countSystemChecks++;
return isSystemUid || isSystemAppId;
}
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 0313aaa6e3a7..97b6b98a0b08 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -53,6 +53,9 @@ import static com.android.os.dnd.DNDProtoEnums.PEOPLE_STARRED;
import static com.android.os.dnd.DNDProtoEnums.ROOT_CONFIG;
import static com.android.os.dnd.DNDProtoEnums.STATE_ALLOW;
import static com.android.os.dnd.DNDProtoEnums.STATE_DISALLOW;
+import static com.android.server.notification.ZenModeHelper.FROM_APP;
+import static com.android.server.notification.ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI;
+import static com.android.server.notification.ZenModeHelper.FROM_USER;
import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE;
import static com.google.common.truth.Truth.assertThat;
@@ -108,6 +111,7 @@ import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.Condition;
+import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenModeConfig.ZenRule;
@@ -1645,8 +1649,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ZenModeConfig config = new ZenModeConfig();
config.automaticRules = new ArrayMap<>();
mZenModeHelper.mConfig = config;
- mZenModeHelper.updateDefaultZenRules(
- Process.SYSTEM_UID, true); // shouldn't throw null pointer
+ mZenModeHelper.updateDefaultZenRules(Process.SYSTEM_UID); // shouldn't throw null pointer
mZenModeHelper.pullRules(events); // shouldn't throw null pointer
}
@@ -1671,7 +1674,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
autoRules.put(SCHEDULE_DEFAULT_RULE_ID, updatedDefaultRule);
mZenModeHelper.mConfig.automaticRules = autoRules;
- mZenModeHelper.updateDefaultZenRules(Process.SYSTEM_UID, true);
+ mZenModeHelper.updateDefaultZenRules(Process.SYSTEM_UID);
assertEquals(updatedDefaultRule,
mZenModeHelper.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID));
}
@@ -1697,7 +1700,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
autoRules.put(SCHEDULE_DEFAULT_RULE_ID, updatedDefaultRule);
mZenModeHelper.mConfig.automaticRules = autoRules;
- mZenModeHelper.updateDefaultZenRules(Process.SYSTEM_UID, true);
+ mZenModeHelper.updateDefaultZenRules(Process.SYSTEM_UID);
assertEquals(updatedDefaultRule,
mZenModeHelper.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID));
}
@@ -1724,7 +1727,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
autoRules.put(SCHEDULE_DEFAULT_RULE_ID, customDefaultRule);
mZenModeHelper.mConfig.automaticRules = autoRules;
- mZenModeHelper.updateDefaultZenRules(Process.SYSTEM_UID, true);
+ mZenModeHelper.updateDefaultZenRules(Process.SYSTEM_UID);
ZenModeConfig.ZenRule ruleAfterUpdating =
mZenModeHelper.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID);
assertEquals(customDefaultRule.enabled, ruleAfterUpdating.enabled);
@@ -1748,7 +1751,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// We need the package name to be something that's not "android" so there aren't any
// existing rules under that package.
String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test",
- CUSTOM_PKG_UID, false);
+ CUSTOM_PKG_UID, FROM_APP);
assertNotNull(id);
}
try {
@@ -1759,7 +1762,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
new ZenPolicy.Builder().build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test",
- CUSTOM_PKG_UID, false);
+ CUSTOM_PKG_UID, FROM_APP);
fail("allowed too many rules to be created");
} catch (IllegalArgumentException e) {
// yay
@@ -1780,7 +1783,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
new ZenPolicy.Builder().build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test",
- CUSTOM_PKG_UID, false);
+ CUSTOM_PKG_UID, FROM_APP);
assertNotNull(id);
}
try {
@@ -1791,7 +1794,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
new ZenPolicy.Builder().build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test",
- CUSTOM_PKG_UID, false);
+ CUSTOM_PKG_UID, FROM_APP);
fail("allowed too many rules to be created");
} catch (IllegalArgumentException e) {
// yay
@@ -1812,7 +1815,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
new ZenPolicy.Builder().build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test",
- CUSTOM_PKG_UID, false);
+ CUSTOM_PKG_UID, FROM_APP);
assertNotNull(id);
}
try {
@@ -1823,7 +1826,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
new ZenPolicy.Builder().build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test",
- CUSTOM_PKG_UID, false);
+ CUSTOM_PKG_UID, FROM_APP);
fail("allowed too many rules to be created");
} catch (IllegalArgumentException e) {
// yay
@@ -1839,7 +1842,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
new ZenPolicy.Builder().build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
assertTrue(id != null);
ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id);
@@ -1860,7 +1863,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
assertTrue(id != null);
ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id);
@@ -1884,7 +1887,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test",
- CUSTOM_PKG_UID, false);
+ CUSTOM_PKG_UID, FROM_APP);
mZenModeHelper.setAutomaticZenRuleState(zenRule.getConditionId(),
new Condition(zenRule.getConditionId(), "", STATE_TRUE),
CUSTOM_PKG_UID, false);
@@ -1903,7 +1906,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test",
- CUSTOM_PKG_UID, false);
+ CUSTOM_PKG_UID, FROM_APP);
AutomaticZenRule zenRule2 = new AutomaticZenRule("NEW",
null,
@@ -1912,7 +1915,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
new ZenPolicy.Builder().build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- mZenModeHelper.updateAutomaticZenRule(id, zenRule2, "", CUSTOM_PKG_UID, false);
+ mZenModeHelper.updateAutomaticZenRule(id, zenRule2, "", CUSTOM_PKG_UID, FROM_APP);
ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id);
assertEquals("NEW", ruleInConfig.name);
@@ -1928,7 +1931,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test",
- CUSTOM_PKG_UID, false);
+ CUSTOM_PKG_UID, FROM_APP);
assertTrue(id != null);
ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id);
@@ -1948,7 +1951,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
new ZenPolicy.Builder().build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test",
- CUSTOM_PKG_UID, false);
+ CUSTOM_PKG_UID, FROM_APP);
assertTrue(id != null);
ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id);
@@ -1972,13 +1975,13 @@ public class ZenModeHelperTest extends UiServiceTestCase {
sharedUri,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
AutomaticZenRule zenRule2 = new AutomaticZenRule("name2",
new ComponentName("android", "ScheduleConditionProvider"),
sharedUri,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id2 = mZenModeHelper.addAutomaticZenRule("android", zenRule2, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
Condition condition = new Condition(sharedUri, "", STATE_TRUE);
mZenModeHelper.setAutomaticZenRuleState(sharedUri, condition, Process.SYSTEM_UID, true);
@@ -2010,6 +2013,182 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
+ public void addAutomaticZenRule_fromApp_ignoresHiddenEffects() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+
+ ZenDeviceEffects zde = new ZenDeviceEffects.Builder()
+ .setShouldDisplayGrayscale(true)
+ .setShouldSuppressAmbientDisplay(true)
+ .setShouldDimWallpaper(true)
+ .setShouldUseNightMode(true)
+ .setShouldDisableAutoBrightness(true)
+ .setShouldDisableTapToWake(true)
+ .setShouldDisableTiltToWake(true)
+ .setShouldDisableTouch(true)
+ .setShouldMinimizeRadioUsage(true)
+ .setShouldMaximizeDoze(true)
+ .build();
+
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setOwner(OWNER)
+ .setDeviceEffects(zde)
+ .build(),
+ "reasons", 0, FROM_APP);
+
+ AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId);
+ assertThat(savedRule.getDeviceEffects()).isEqualTo(
+ new ZenDeviceEffects.Builder()
+ .setShouldDisplayGrayscale(true)
+ .setShouldSuppressAmbientDisplay(true)
+ .setShouldDimWallpaper(true)
+ .setShouldUseNightMode(true)
+ .build());
+ }
+
+ @Test
+ public void addAutomaticZenRule_fromSystem_respectsHiddenEffects() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+
+ ZenDeviceEffects zde = new ZenDeviceEffects.Builder()
+ .setShouldDisplayGrayscale(true)
+ .setShouldSuppressAmbientDisplay(true)
+ .setShouldDimWallpaper(true)
+ .setShouldUseNightMode(true)
+ .setShouldDisableAutoBrightness(true)
+ .setShouldDisableTapToWake(true)
+ .setShouldDisableTiltToWake(true)
+ .setShouldDisableTouch(true)
+ .setShouldMinimizeRadioUsage(true)
+ .setShouldMaximizeDoze(true)
+ .build();
+
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setOwner(OWNER)
+ .setDeviceEffects(zde)
+ .build(),
+ "reasons", 0, FROM_SYSTEM_OR_SYSTEMUI);
+
+ AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId);
+ assertThat(savedRule.getDeviceEffects()).isEqualTo(zde);
+ }
+
+ @Test
+ public void addAutomaticZenRule_fromUser_respectsHiddenEffects() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+
+ ZenDeviceEffects zde = new ZenDeviceEffects.Builder()
+ .setShouldDisplayGrayscale(true)
+ .setShouldSuppressAmbientDisplay(true)
+ .setShouldDimWallpaper(true)
+ .setShouldUseNightMode(true)
+ .setShouldDisableAutoBrightness(true)
+ .setShouldDisableTapToWake(true)
+ .setShouldDisableTiltToWake(true)
+ .setShouldDisableTouch(true)
+ .setShouldMinimizeRadioUsage(true)
+ .setShouldMaximizeDoze(true)
+ .build();
+
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setOwner(OWNER)
+ .setDeviceEffects(zde)
+ .build(),
+ "reasons", 0, FROM_USER);
+
+ AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId);
+ assertThat(savedRule.getDeviceEffects()).isEqualTo(zde);
+ }
+
+ @Test
+ public void updateAutomaticZenRule_fromApp_preservesPreviousHiddenEffects() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+ ZenDeviceEffects original = new ZenDeviceEffects.Builder()
+ .setShouldDisableTapToWake(true)
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setOwner(OWNER)
+ .setDeviceEffects(original)
+ .build(),
+ "reasons", 0, FROM_SYSTEM_OR_SYSTEMUI);
+
+ ZenDeviceEffects updateFromApp = new ZenDeviceEffects.Builder()
+ .setShouldUseNightMode(true) // Good
+ .setShouldMaximizeDoze(true) // Bad
+ .build();
+ mZenModeHelper.updateAutomaticZenRule(ruleId,
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setOwner(OWNER)
+ .setDeviceEffects(updateFromApp)
+ .build(),
+ "reasons", 0, FROM_APP);
+
+ AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId);
+ assertThat(savedRule.getDeviceEffects()).isEqualTo(
+ new ZenDeviceEffects.Builder()
+ .setShouldUseNightMode(true) // From update.
+ .setShouldDisableTapToWake(true) // From original.
+ .build());
+ }
+
+ @Test
+ public void updateAutomaticZenRule_fromSystem_updatesHiddenEffects() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+ ZenDeviceEffects original = new ZenDeviceEffects.Builder()
+ .setShouldDisableTapToWake(true)
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setOwner(OWNER)
+ .setDeviceEffects(original)
+ .build(),
+ "reasons", 0, FROM_SYSTEM_OR_SYSTEMUI);
+
+ ZenDeviceEffects updateFromSystem = new ZenDeviceEffects.Builder()
+ .setShouldUseNightMode(true) // Good
+ .setShouldMaximizeDoze(true) // Also good
+ .build();
+ mZenModeHelper.updateAutomaticZenRule(ruleId,
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setDeviceEffects(updateFromSystem)
+ .build(),
+ "reasons", 0, FROM_SYSTEM_OR_SYSTEMUI);
+
+ AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId);
+ assertThat(savedRule.getDeviceEffects()).isEqualTo(updateFromSystem);
+ }
+
+ @Test
+ public void updateAutomaticZenRule_fromUser_updatesHiddenEffects() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+ ZenDeviceEffects original = new ZenDeviceEffects.Builder()
+ .setShouldDisableTapToWake(true)
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setOwner(OWNER)
+ .setDeviceEffects(original)
+ .build(),
+ "reasons", 0, FROM_SYSTEM_OR_SYSTEMUI);
+
+ ZenDeviceEffects updateFromUser = new ZenDeviceEffects.Builder()
+ .setShouldUseNightMode(true) // Good
+ .setShouldMaximizeDoze(true) // Also good
+ .build();
+ mZenModeHelper.updateAutomaticZenRule(ruleId,
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setDeviceEffects(updateFromUser)
+ .build(),
+ "reasons", 0, FROM_USER);
+
+ AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId);
+ assertThat(savedRule.getDeviceEffects()).isEqualTo(updateFromUser);
+ }
+
+ @Test
public void testSetManualZenMode() {
mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
setupZenConfig();
@@ -2119,7 +2298,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule,
- "test", Process.SYSTEM_UID, true);
+ "test", Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// Event 1: Mimic the rule coming on automatically by setting the Condition to STATE_TRUE
mZenModeHelper.setAutomaticZenRuleState(id,
@@ -2128,7 +2307,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Event 2: "User" turns off the automatic rule (sets it to not enabled)
zenRule.setEnabled(false);
- mZenModeHelper.updateAutomaticZenRule(id, zenRule, "", Process.SYSTEM_UID, true);
+ mZenModeHelper.updateAutomaticZenRule(id, zenRule, "", Process.SYSTEM_UID,
+ FROM_SYSTEM_OR_SYSTEMUI);
// Add a new system rule
AutomaticZenRule systemRule = new AutomaticZenRule("systemRule",
@@ -2138,7 +2318,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String systemId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), systemRule,
- "test", Process.SYSTEM_UID, true);
+ "test", Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// Event 3: turn on the system rule
mZenModeHelper.setAutomaticZenRuleState(systemId,
@@ -2270,7 +2450,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// Rule 2, same as rule 1
AutomaticZenRule zenRule2 = new AutomaticZenRule("name2",
@@ -2280,7 +2460,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// Rule 3, has stricter settings than the default settings
ZenModeConfig ruleConfig = mZenModeHelper.mConfig.copy();
@@ -2294,7 +2474,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ruleConfig.toZenPolicy(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id3 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule3, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// First: turn on rule 1
mZenModeHelper.setAutomaticZenRuleState(id,
@@ -2394,7 +2574,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// Rule 2, same as rule 1 but owned by the system
AutomaticZenRule zenRule2 = new AutomaticZenRule("name2",
@@ -2404,7 +2584,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// Turn on rule 1; call looks like it's from the system. Because setting a condition is
// typically an automatic (non-user-initiated) action, expect the calling UID to be
@@ -2422,7 +2602,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Disable rule 1. Because this looks like a user action, the UID should not be modified
// from the system-provided one.
zenRule.setEnabled(false);
- mZenModeHelper.updateAutomaticZenRule(id, zenRule, "", Process.SYSTEM_UID, true);
+ mZenModeHelper.updateAutomaticZenRule(id, zenRule, "", Process.SYSTEM_UID,
+ FROM_SYSTEM_OR_SYSTEMUI);
// Add a manual rule. Any manual rule changes should not get calling uids reassigned.
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, null, "",
@@ -2553,7 +2734,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// enable the rule
mZenModeHelper.setAutomaticZenRuleState(id,
@@ -2596,7 +2777,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customPolicy,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// enable the rule; this will update the consolidated policy
mZenModeHelper.setAutomaticZenRuleState(id,
@@ -2632,7 +2813,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// enable rule 1
mZenModeHelper.setAutomaticZenRuleState(id,
@@ -2656,7 +2837,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customPolicy,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2,
- "test", Process.SYSTEM_UID, true);
+ "test", Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// enable rule 2; this will update the consolidated policy
mZenModeHelper.setAutomaticZenRuleState(id2,
@@ -2694,7 +2875,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customPolicy,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test",
- Process.SYSTEM_UID, true);
+ Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// enable the rule; this will update the consolidated policy
mZenModeHelper.setAutomaticZenRuleState(id,
@@ -2716,7 +2897,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
strictPolicy,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2,
- "test", Process.SYSTEM_UID, true);
+ "test", Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// enable rule 2; this will update the consolidated policy
mZenModeHelper.setAutomaticZenRuleState(id2,
@@ -2784,7 +2965,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
final String createdId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
- zenRule, "test", Process.SYSTEM_UID, true);
+ zenRule, "test", Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
CountDownLatch latch = new CountDownLatch(1);
final int[] actualStatus = new int[1];
@@ -2800,7 +2981,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelper.addCallback(callback);
zenRule.setEnabled(false);
- mZenModeHelper.updateAutomaticZenRule(createdId, zenRule, "", Process.SYSTEM_UID, true);
+ mZenModeHelper.updateAutomaticZenRule(createdId, zenRule, "", Process.SYSTEM_UID,
+ FROM_SYSTEM_OR_SYSTEMUI);
assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
assertEquals(AUTOMATIC_RULE_STATUS_DISABLED, actualStatus[0]);
@@ -2818,7 +3000,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, false);
final String createdId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
- zenRule, "test", Process.SYSTEM_UID, true);
+ zenRule, "test", Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
CountDownLatch latch = new CountDownLatch(1);
final int[] actualStatus = new int[1];
@@ -2834,7 +3016,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelper.addCallback(callback);
zenRule.setEnabled(true);
- mZenModeHelper.updateAutomaticZenRule(createdId, zenRule, "", Process.SYSTEM_UID, true);
+ mZenModeHelper.updateAutomaticZenRule(createdId, zenRule, "", Process.SYSTEM_UID,
+ FROM_SYSTEM_OR_SYSTEMUI);
assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
assertEquals(AUTOMATIC_RULE_STATUS_ENABLED, actualStatus[0]);
@@ -2853,7 +3036,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
final String createdId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
- zenRule, "test", Process.SYSTEM_UID, true);
+ zenRule, "test", Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
CountDownLatch latch = new CountDownLatch(1);
final int[] actualStatus = new int[1];
@@ -2889,7 +3072,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
final String createdId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
- zenRule, "test", Process.SYSTEM_UID, true);
+ zenRule, "test", Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
CountDownLatch latch = new CountDownLatch(1);
final int[] actualStatus = new int[2];
@@ -2929,7 +3112,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
final String createdId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
- zenRule, "test", Process.SYSTEM_UID, true);
+ zenRule, "test", Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
CountDownLatch latch = new CountDownLatch(1);
final int[] actualStatus = new int[2];
@@ -2969,7 +3152,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
final String createdId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
- zenRule, "test", Process.SYSTEM_UID, true);
+ zenRule, "test", Process.SYSTEM_UID, FROM_SYSTEM_OR_SYSTEMUI);
// Event 1: Mimic the rule coming on automatically by setting the Condition to STATE_TRUE
mZenModeHelper.setAutomaticZenRuleState(createdId,
@@ -2982,7 +3165,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Event 3: "User" turns off the automatic rule (sets it to not enabled)
zenRule.setEnabled(false);
- mZenModeHelper.updateAutomaticZenRule(createdId, zenRule, "", Process.SYSTEM_UID, true);
+ mZenModeHelper.updateAutomaticZenRule(createdId, zenRule, "", Process.SYSTEM_UID,
+ FROM_SYSTEM_OR_SYSTEMUI);
assertEquals(false, mZenModeHelper.mConfig.automaticRules.get(createdId).snoozing);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
index e7ac33fc6a1a..76018683c987 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
@@ -30,6 +30,7 @@ import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_90;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -130,13 +131,17 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
});
mDisplayRotationCompatPolicy = new DisplayRotationCompatPolicy(
mDisplayContent, mMockHandler);
+
+ // Do not show the real toast.
+ spyOn(mDisplayRotationCompatPolicy);
+ doNothing().when(mDisplayRotationCompatPolicy).showToast(anyInt());
+ doNothing().when(mDisplayRotationCompatPolicy).showToast(anyInt(), anyString());
}
@Test
public void testOpenedCameraInSplitScreen_showToast() throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
spyOn(mTask);
- spyOn(mDisplayRotationCompatPolicy);
doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mActivity).getWindowingMode();
doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mTask).getWindowingMode();
@@ -160,7 +165,6 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
public void testOpenedCameraInSplitScreen_orientationNotFixed_doNotShowToast() {
configureActivity(SCREEN_ORIENTATION_UNSPECIFIED);
spyOn(mTask);
- spyOn(mDisplayRotationCompatPolicy);
doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mActivity).getWindowingMode();
doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mTask).getWindowingMode();
@@ -175,7 +179,6 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
public void testOnScreenRotationAnimationFinished_treatmentNotEnabled_doNotShowToast() {
when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled())
.thenReturn(false);
- spyOn(mDisplayRotationCompatPolicy);
mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
@@ -185,8 +188,6 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
@Test
public void testOnScreenRotationAnimationFinished_noOpenCamera_doNotShowToast() {
- spyOn(mDisplayRotationCompatPolicy);
-
mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
verify(mDisplayRotationCompatPolicy, never()).showToast(
@@ -197,7 +198,6 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
public void testOnScreenRotationAnimationFinished_notFullscreen_doNotShowToast() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
doReturn(true).when(mActivity).inMultiWindowMode();
- spyOn(mDisplayRotationCompatPolicy);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
@@ -211,7 +211,6 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
public void testOnScreenRotationAnimationFinished_orientationNotFixed_doNotShowToast() {
configureActivity(SCREEN_ORIENTATION_UNSPECIFIED);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
- spyOn(mDisplayRotationCompatPolicy);
mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
@@ -223,7 +222,6 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
public void testOnScreenRotationAnimationFinished_showToast() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
- spyOn(mDisplayRotationCompatPolicy);
mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 2b19ad97e90c..1be61c36f272 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -114,8 +115,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase {
mDisplayUniqueId = "test:" + sNextUniqueId++;
mTestDisplay = new TestDisplayContent.Builder(mAtm, 1000, 1500)
.setUniqueId(mDisplayUniqueId).build();
- when(mRootWindowContainer.getDisplayContent(eq(mDisplayUniqueId)))
- .thenReturn(mTestDisplay);
+ doReturn(mTestDisplay).when(mRootWindowContainer).getDisplayContent(mDisplayUniqueId);
Task rootTask = mTestDisplay.getDefaultTaskDisplayArea()
.createRootTask(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true);
@@ -200,7 +200,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase {
public void testReturnsEmptyDisplayIfDisplayIsNotFound() {
mTarget.saveTask(mTestTask);
- when(mRootWindowContainer.getDisplayContent(eq(mDisplayUniqueId))).thenReturn(null);
+ doReturn(null).when(mRootWindowContainer).getDisplayContent(eq(mDisplayUniqueId));
mTarget.getLaunchParams(mTestTask, null, mResult);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index eb78906f570d..5a434988e548 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -317,6 +317,31 @@ public class RootWindowContainerTests extends WindowTestsBase {
assertTrue(firstActivity.mRequestForceTransition);
}
+ @Test
+ public void testMultipleActivitiesTaskEnterPip() {
+ // Enable shell transition because the order of setting windowing mode is different.
+ registerTestTransitionPlayer();
+ final ActivityRecord transientActivity = new ActivityBuilder(mAtm)
+ .setCreateTask(true).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm)
+ .setTask(activity1.getTask()).build();
+ activity2.setState(RESUMED, "test");
+
+ // Assume the top activity switches to a transient-launch, e.g. recents.
+ transientActivity.setState(RESUMED, "test");
+ transientActivity.getTask().moveToFront("test");
+
+ mRootWindowContainer.moveActivityToPinnedRootTask(activity2,
+ null /* launchIntoPipHostActivity */, "test");
+ assertEquals("Created PiP task must not change focus", transientActivity.getTask(),
+ mRootWindowContainer.getTopDisplayFocusedRootTask());
+ final Task newPipTask = activity2.getTask();
+ assertEquals(newPipTask, mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask());
+ assertNotEquals(newPipTask, activity1.getTask());
+ assertFalse("Created PiP task must not be in recents", newPipTask.inRecents);
+ }
+
/**
* When there is only one activity in the Task, and the activity is requesting to enter PIP, the
* whole Task should enter PIP.
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 5738d246dea9..b1def8d0b3a6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -38,6 +38,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
@@ -57,7 +58,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.hardware.devicestate.DeviceStateManager;
-import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.net.Uri;
import android.os.Handler;
@@ -102,6 +103,7 @@ import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
+import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -240,6 +242,12 @@ public class SystemServicesTestRule implements TestRule {
doNothing().when(contentResolver)
.registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class),
anyInt());
+
+ // Unit test should not register listener to the real service.
+ final DisplayManagerGlobal dmg = DisplayManagerGlobal.getInstance();
+ spyOn(dmg);
+ doNothing().when(dmg).registerDisplayListener(
+ any(), any(Executor.class), anyLong(), anyString());
}
private void setUpLocalServices() {
@@ -383,9 +391,6 @@ public class SystemServicesTestRule implements TestRule {
mWmService.onInitReady();
mAtmService.setWindowManager(mWmService);
- // Avoid real display events interfering with the test. Also avoid leaking registration.
- mContext.getSystemService(DisplayManager.class)
- .unregisterDisplayListener(mAtmService.mRootWindowContainer);
mWmService.mDisplayEnabled = true;
mWmService.mDisplayReady = true;
mAtmService.getTransitionController().mIsWaitingForDisplayEnabled = false;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index d8a9a282a622..2007f680f1ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -757,7 +757,6 @@ public class WindowStateTests extends WindowTestsBase {
startingApp.getWindowFrames().setInsetsChanged(true);
startingApp.updateResizingWindowIfNeeded();
assertTrue(startingApp.isDrawn());
- assertFalse(startingApp.getOrientationChanging());
}
@SetupWindows(addWindows = W_ABOVE_ACTIVITY)
diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java
index d075b5f01ef9..5434c82b07bd 100644
--- a/tests/Input/src/com/android/test/input/InputDeviceTest.java
+++ b/tests/Input/src/com/android/test/input/InputDeviceTest.java
@@ -51,6 +51,7 @@ public class InputDeviceTest {
assertEquals(device.getName(), outDevice.getName());
assertEquals(device.getVendorId(), outDevice.getVendorId());
assertEquals(device.getProductId(), outDevice.getProductId());
+ assertEquals(device.getDeviceBus(), outDevice.getDeviceBus());
assertEquals(device.getDescriptor(), outDevice.getDescriptor());
assertEquals(device.isExternal(), outDevice.isExternal());
assertEquals(device.getSources(), outDevice.getSources());
@@ -79,6 +80,7 @@ public class InputDeviceTest {
.setName("Test Device " + DEVICE_ID)
.setVendorId(44)
.setProductId(45)
+ .setDeviceBus(3)
.setDescriptor("descriptor")
.setExternal(true)
.setSources(InputDevice.SOURCE_HDMI)