summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobInfo.java2
-rw-r--r--api/StubLibraries.bp8
-rw-r--r--core/api/current.txt2
-rw-r--r--core/api/test-current.txt9
-rw-r--r--core/java/android/accounts/AccountManager.java2
-rw-r--r--core/java/android/app/Activity.java2
-rw-r--r--core/java/android/app/ActivityManagerInternal.java11
-rw-r--r--core/java/android/app/AppOpsManager.java3
-rw-r--r--core/java/android/app/Notification.java9
-rw-r--r--core/java/android/app/TEST_MAPPING16
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java8
-rw-r--r--core/java/android/app/admin/flags/flags.aconfig5
-rw-r--r--core/java/android/app/prediction/AppPredictionContext.java9
-rw-r--r--core/java/android/app/prediction/AppTarget.java10
-rw-r--r--core/java/android/app/prediction/AppTargetEvent.java8
-rw-r--r--core/java/android/app/prediction/OWNERS2
-rw-r--r--core/java/android/app/servertransaction/ClientTransactionListenerController.java26
-rw-r--r--core/java/android/content/Intent.java7
-rw-r--r--core/java/android/content/TEST_MAPPING8
-rw-r--r--core/java/android/content/pm/PackageManager.java15
-rw-r--r--core/java/android/content/pm/multiuser.aconfig10
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java4
-rw-r--r--core/java/android/hardware/usb/DeviceFilter.java48
-rw-r--r--core/java/android/hardware/usb/flags/usb_framework_flags.aconfig8
-rw-r--r--core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java5
-rw-r--r--core/java/android/view/FocusFinder.java4
-rw-r--r--core/java/android/view/InsetsController.java12
-rw-r--r--core/java/android/view/ViewRootImpl.java24
-rw-r--r--core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java13
-rw-r--r--core/java/android/view/inputmethod/ImeTracker.java94
-rw-r--r--core/java/android/window/TaskFragmentParentInfo.java36
-rw-r--r--core/java/android/window/TaskFragmentTransaction.java23
-rw-r--r--core/java/android/window/flags/large_screen_experiences_app_compat.aconfig10
-rw-r--r--core/java/com/android/internal/inputmethod/IImeTracker.aidl12
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodDebug.java2
-rw-r--r--core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java7
-rw-r--r--core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java14
-rw-r--r--core/res/res/values/config.xml2
-rw-r--r--core/res/res/values/config_battery_stats.xml22
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java15
-rw-r--r--data/etc/core.protolog.pbbin54058 -> 54020 bytes
-rw-r--r--data/etc/services.core.protolog.json12
-rw-r--r--graphics/java/android/graphics/ColorSpace.java6
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java223
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java104
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java66
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java102
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java66
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java167
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java56
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java5
-rw-r--r--media/java/android/media/session/MediaController.java14
-rw-r--r--nfc/java/android/nfc/cardemulation/HostApduService.java2
-rw-r--r--packages/SettingsLib/DataStore/README.md289
-rw-r--r--packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreEntity.kt11
-rw-r--r--packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorage.kt28
-rw-r--r--packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageTest.kt9
-rw-r--r--packages/SettingsLib/SettingsTheme/res/color-v35/settingslib_preference_bg_color.xml8
-rw-r--r--packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background.xml4
-rw-r--r--packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom.xml10
-rw-r--r--packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml33
-rw-r--r--packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center.xml4
-rw-r--r--packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml30
-rw-r--r--packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml30
-rw-r--r--packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top.xml10
-rw-r--r--packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml33
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v35/dimens.xml20
-rw-r--r--packages/SettingsLib/res/values/strings.xml4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/satellite/SatelliteDialogUtils.kt145
-rw-r--r--packages/SettingsLib/tests/robotests/Android.bp5
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java27
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt162
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/Android.bp46
-rw-r--r--packages/SystemUI/AndroidManifest.xml14
-rw-r--r--packages/SystemUI/aconfig/accessibility.aconfig16
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig43
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt25
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt3
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt3
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryImplTest.kt98
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorTest.kt14
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java20
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/FingerprintPropertyRepositoryTest.kt103
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractorTest.kt112
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractorTest.kt81
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapperTest.kt114
-rw-r--r--packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml2
-rw-r--r--packages/SystemUI/res/drawable/contrast_dialog_button_background.xml46
-rw-r--r--packages/SystemUI/res/drawable/hub_handle.xml20
-rw-r--r--packages/SystemUI/res/drawable/ic_contrast_high.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_contrast_medium.xml23
-rw-r--r--packages/SystemUI/res/drawable/ic_contrast_standard.xml23
-rw-r--r--packages/SystemUI/res/drawable/ongoing_activity_chip_bg.xml (renamed from packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml)2
-rw-r--r--packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml17
-rw-r--r--packages/SystemUI/res/layout/biometric_prompt_button_bar.xml10
-rw-r--r--packages/SystemUI/res/layout/contrast_dialog.xml127
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_container.xml13
-rw-r--r--packages/SystemUI/res/layout/ongoing_activity_chip.xml (renamed from packages/SystemUI/res/layout/ongoing_call_chip.xml)26
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml19
-rw-r--r--packages/SystemUI/res/values/strings.xml9
-rw-r--r--packages/SystemUI/res/values/styles.xml4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java120
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.kt101
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepository.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt111
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TileStateToProto.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt85
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractor.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/model/QRCodeScannerTileModel.kt (renamed from packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt)23
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapper.kt59
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainer.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallBackgroundContainer.kt)8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometer.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometer.kt)38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ServiceStateModel.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt67
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt112
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallBackgroundContainerTest.kt)13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt)19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt145
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/TextPrecomputerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt4
-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/statusbar/notification/stack/NotificationStackScrollLayoutTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt68
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt136
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java110
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java20
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeBrightnessPolicyRepository.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qrcodescanner/QRCodeScannerControllerKosmos.kt23
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerKosmos.kt21
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorKosmos.kt21
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt74
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt2
-rw-r--r--services/accessibility/accessibility.aconfig20
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java300
-rw-r--r--services/companion/java/com/android/server/companion/virtual/TEST_MAPPING11
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java23
-rw-r--r--services/core/java/com/android/server/SystemConfig.java8
-rw-r--r--services/core/java/com/android/server/TEST_MAPPING21
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java20
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java46
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java11
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java59
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java6
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java7
-rw-r--r--services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java39
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java18
-rw-r--r--services/core/java/com/android/server/inputmethod/ImeTrackerService.java7
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodBindingController.java27
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodInfoUtils.java21
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java361
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodMap.java34
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java4
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java2
-rw-r--r--services/core/java/com/android/server/notification/NotificationAttentionHelper.java50
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java100
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java21
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageFreezer.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java17
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java64
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java54
-rw-r--r--services/core/java/com/android/server/pm/PackageMetrics.java11
-rw-r--r--services/core/java/com/android/server/pm/Settings.java3
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java24
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryStatsImpl.java78
-rw-r--r--services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java9
-rw-r--r--services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java8
-rw-r--r--services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java9
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java13
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java90
-rw-r--r--services/core/java/com/android/server/wm/ActivityRefresher.java131
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java99
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java2
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java17
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java31
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp10
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java23
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java19
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java13
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java24
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java25
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodInfoUtilsTest.java84
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java20
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMapTest.java93
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/TestUtils.java101
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java34
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java13
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java9
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java7
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java9
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java12
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java7
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java7
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsProcessorTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java67
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java105
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java71
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java219
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java4
-rw-r--r--tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml4
-rw-r--r--tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt3
-rw-r--r--tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt3
-rw-r--r--tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt40
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml107
-rw-r--r--tests/Input/src/android/hardware/input/KeyboardLayoutPreviewTests.kt6
-rw-r--r--tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt9
-rw-r--r--tests/Internal/src/com/android/internal/protolog/ProtologDataSourceTest.java (renamed from tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java)2
-rw-r--r--tests/UsbManagerTests/src/android/hardware/usb/DeviceFilterTest.java248
480 files changed, 7303 insertions, 2797 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index c74c48ce6ba8..5f57c3973ab0 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -31,6 +31,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.app.Notification;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
@@ -1366,6 +1367,7 @@ public class JobInfo implements Parcelable {
* @return This object for method chaining
*/
@FlaggedApi(Flags.FLAG_JOB_DEBUG_INFO_APIS)
+ @SuppressLint("BuilderSetStyle")
@NonNull
public Builder removeDebugTag(@NonNull String tag) {
mDebugTags.remove(tag);
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 9b81bd441015..13d6ae5be3e8 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -50,7 +50,7 @@ non_updatable_exportable_droidstubs {
},
api_lint: {
enabled: true,
- new_since: ":android.api.public.latest",
+ new_since: ":android.api.combined.public.latest",
baseline_file: ":non-updatable-lint-baseline.txt",
},
},
@@ -130,7 +130,7 @@ non_updatable_exportable_droidstubs {
},
api_lint: {
enabled: true,
- new_since: ":android.api.system.latest",
+ new_since: ":android.api.combined.system.latest",
baseline_file: ":non-updatable-system-lint-baseline.txt",
},
},
@@ -185,7 +185,7 @@ non_updatable_exportable_droidstubs {
},
api_lint: {
enabled: true,
- new_since: ":android.api.test.latest",
+ new_since: ":android.api.combined.test.latest",
baseline_file: ":non-updatable-test-lint-baseline.txt",
},
},
@@ -269,7 +269,7 @@ non_updatable_exportable_droidstubs {
},
api_lint: {
enabled: true,
- new_since: ":android.api.module-lib.latest",
+ new_since: ":android.api.combined.module-lib.latest",
baseline_file: ":non-updatable-module-lib-lint-baseline.txt",
},
},
diff --git a/core/api/current.txt b/core/api/current.txt
index 53cf7d59f974..13958d24096b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -26592,7 +26592,7 @@ package android.media.session {
method public long getFlags();
method @Nullable public android.media.MediaMetadata getMetadata();
method public String getPackageName();
- method @Nullable public android.media.session.MediaController.PlaybackInfo getPlaybackInfo();
+ method @NonNull public android.media.session.MediaController.PlaybackInfo getPlaybackInfo();
method @Nullable public android.media.session.PlaybackState getPlaybackState();
method @Nullable public java.util.List<android.media.session.MediaSession.QueueItem> getQueue();
method @Nullable public CharSequence getQueueTitle();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 624227dc26f3..14ae3f543436 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -4260,6 +4260,12 @@ package android.window {
field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentOrganizerToken> CREATOR;
}
+ public final class TaskFragmentParentInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentParentInfo> CREATOR;
+ }
+
public final class TaskFragmentTransaction implements android.os.Parcelable {
ctor public TaskFragmentTransaction();
method public void addChange(@Nullable android.window.TaskFragmentTransaction.Change);
@@ -4284,8 +4290,8 @@ package android.window {
method @Nullable public android.os.IBinder getActivityToken();
method @NonNull public android.os.Bundle getErrorBundle();
method @Nullable public android.os.IBinder getErrorCallbackToken();
- method @Nullable public android.content.res.Configuration getTaskConfiguration();
method @Nullable public android.window.TaskFragmentInfo getTaskFragmentInfo();
+ method @Nullable public android.window.TaskFragmentParentInfo getTaskFragmentParentInfo();
method @Nullable public android.os.IBinder getTaskFragmentToken();
method public int getTaskId();
method public int getType();
@@ -4293,7 +4299,6 @@ package android.window {
method @NonNull public android.window.TaskFragmentTransaction.Change setActivityToken(@NonNull android.os.IBinder);
method @NonNull public android.window.TaskFragmentTransaction.Change setErrorBundle(@NonNull android.os.Bundle);
method @NonNull public android.window.TaskFragmentTransaction.Change setErrorCallbackToken(@Nullable android.os.IBinder);
- method @NonNull public android.window.TaskFragmentTransaction.Change setTaskConfiguration(@NonNull android.content.res.Configuration);
method @NonNull public android.window.TaskFragmentTransaction.Change setTaskFragmentInfo(@NonNull android.window.TaskFragmentInfo);
method @NonNull public android.window.TaskFragmentTransaction.Change setTaskFragmentToken(@NonNull android.os.IBinder);
method @NonNull public android.window.TaskFragmentTransaction.Change setTaskId(int);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 7ee3413550af..497d47adc7cc 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -2015,7 +2015,7 @@ public class AccountManager {
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
- * @return An {@link AccountManagerFuture} which resolves to a Boolean indicated wether it
+ * @return An {@link AccountManagerFuture} which resolves to a Boolean indicated whether it
* succeeded.
* @hide
*/
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a5dd4a7207c3..e1cb630f4d82 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5796,6 +5796,8 @@ public class Activity extends ContextThemeWrapper
* @see #onRequestPermissionsResult
*/
@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ @SuppressLint("OnNameExpected")
+ // Suppress lint as this is an overload of the original API.
public boolean shouldShowRequestPermissionRationale(@NonNull String permission, int deviceId) {
final PackageManager packageManager = getDeviceId() == deviceId ? getPackageManager()
: createDeviceContext(deviceId).getPackageManager();
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d8df447982a0..8e99e46be6ac 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -1282,4 +1282,15 @@ public abstract class ActivityManagerInternal {
*/
public abstract void addStartInfoTimestamp(int key, long timestampNs, int uid, int pid,
int userId);
+
+ /**
+ * It is similar {@link IActivityManager#killApplication(String, int, int, String, int)} but
+ * it immediately stop the package.
+ *
+ * <p>Note: Do not call this method from inside PMS's lock, otherwise it'll run into
+ * watchdog reset.
+ * @hide
+ */
+ public abstract void killApplicationSync(String pkgName, int appId, int userId,
+ String reason, int exitInfoReason);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 54f69099e081..6865f9c5013b 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -3583,6 +3583,9 @@ public class AppOpsManager {
return mAttributionTag;
}
+ /**
+ * Persistent device Id of the proxy that noted the op
+ */
@FlaggedApi(Flags.FLAG_DEVICE_ID_IN_OP_PROXY_INFO_ENABLED)
public @Nullable String getDeviceId() { return mDeviceId; }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8b19664c6abf..0672064bd5ea 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6492,8 +6492,13 @@ public class Notification implements Parcelable
// visual regressions.
@SuppressWarnings("AndroidFrameworkCompatChange")
private boolean bigContentViewRequired() {
- if (!Flags.notificationExpansionOptional()
- && mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S) {
+ if (Flags.notificationExpansionOptional()) {
+ // Notifications without a bigContentView, style, or actions do not need to expand
+ boolean exempt = mN.bigContentView == null
+ && mStyle == null && mActions.size() == 0;
+ return !exempt;
+ }
+ if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S) {
return true;
}
// Notifications with contentView and without a bigContentView, style, or actions would
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index dc44764dc046..0deb842aff61 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -378,6 +378,14 @@
}
],
"file_patterns": ["(/|^)ContextImpl.java"]
+ },
+ {
+ "file_patterns": [
+ "(/|^)Activity.*.java",
+ "(/|^)PendingIntent.java",
+ "(/|^)ComtextImpl.java"
+ ],
+ "name": "CtsWindowManagerBackgroundActivityTestCases"
}
],
"postsubmit": [
@@ -392,14 +400,6 @@
{
"file_patterns": ["(/|^)AppOpsManager.java"],
"name": "CtsAppOpsTestCases"
- },
- {
- "file_patterns": [
- "(/|^)Activity.*.java",
- "(/|^)PendingIntent.java",
- "(/|^)ComtextImpl.java"
- ],
- "name": "CtsWindowManagerBackgroundActivityTestCases"
}
]
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 69f29f3ab081..c529f7d95190 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1698,7 +1698,7 @@ public class DevicePolicyManager {
/**
* A boolean extra indicating whether device encryption can be skipped as part of
- * <a href="#managed-provisioning>provisioning</a>.
+ * <a href="#managed-provisioning">provisioning</a>.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} or an intent with action
* {@link #ACTION_PROVISION_MANAGED_DEVICE} that starts device owner provisioning.
@@ -10427,7 +10427,7 @@ public class DevicePolicyManager {
@WorkerThread
public void setApplicationRestrictions(@Nullable ComponentName admin, String packageName,
Bundle settings) {
- if (!Flags.dmrhCanSetAppRestriction()) {
+ if (!Flags.dmrhSetAppRestrictions()) {
throwIfParentInstance("setApplicationRestrictions");
}
@@ -11835,7 +11835,7 @@ public class DevicePolicyManager {
@WorkerThread
public @NonNull Bundle getApplicationRestrictions(
@Nullable ComponentName admin, String packageName) {
- if (!Flags.dmrhCanSetAppRestriction()) {
+ if (!Flags.dmrhSetAppRestrictions()) {
throwIfParentInstance("getApplicationRestrictions");
}
@@ -14120,7 +14120,7 @@ public class DevicePolicyManager {
public @NonNull DevicePolicyManager getParentProfileInstance(@NonNull ComponentName admin) {
throwIfParentInstance("getParentProfileInstance");
try {
- if (Flags.dmrhCanSetAppRestriction()) {
+ if (Flags.dmrhSetAppRestrictions()) {
UserManager um = mContext.getSystemService(UserManager.class);
if (!um.isManagedProfile()) {
throw new SecurityException("The current user does not have a parent profile.");
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 3d6ec19299cb..4154e667360b 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -244,10 +244,13 @@ flag {
}
flag {
- name: "dmrh_can_set_app_restriction"
+ name: "dmrh_set_app_restrictions"
namespace: "enterprise"
description: "Allow DMRH to set application restrictions (both on the profile and the parent)"
bug: "328758346"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
index 99fa869cee93..1b718d436d6d 100644
--- a/core/java/android/app/prediction/AppPredictionContext.java
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -24,6 +24,8 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* Class that provides contextual information about the environment in which the app prediction is
* used, such as package name, UI in which the app targets are shown, and number of targets.
@@ -99,6 +101,13 @@ public final class AppPredictionContext implements Parcelable {
}
@Override
+ public int hashCode() {
+ int hashCode = Objects.hash(mUiSurface, mPackageName);
+ hashCode = 31 * hashCode + mPredictedTargetCount;
+ return hashCode;
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index fef9e7020097..25c1a594ad81 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -167,6 +167,16 @@ public final class AppTarget implements Parcelable {
}
@Override
+ public int hashCode() {
+ int hashCode = Objects.hash(mId, mPackageName, mClassName, mUser);
+ if (mShortcutInfo != null) {
+ hashCode = 31 * hashCode + mShortcutInfo.getId().hashCode();
+ }
+ hashCode = 31 * hashCode + mRank;
+ return hashCode;
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index 91da8ec71dae..e36d87899b62 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -24,6 +24,7 @@ import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* A representation of an app target event.
@@ -116,6 +117,13 @@ public final class AppTargetEvent implements Parcelable {
}
@Override
+ public int hashCode() {
+ int hashCode = Objects.hash(mTarget, mLocation);
+ hashCode = 31 * hashCode + mAction;
+ return hashCode;
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/app/prediction/OWNERS b/core/java/android/app/prediction/OWNERS
index fe012da8e307..73168fb90dbc 100644
--- a/core/java/android/app/prediction/OWNERS
+++ b/core/java/android/app/prediction/OWNERS
@@ -1,2 +1,4 @@
+pinyaoting@google.com
+hyunyoungs@google.com
adamcohen@google.com
sunnygoyal@google.com
diff --git a/core/java/android/app/servertransaction/ClientTransactionListenerController.java b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
index cda286742d28..9b53461568ca 100644
--- a/core/java/android/app/servertransaction/ClientTransactionListenerController.java
+++ b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
@@ -33,11 +33,13 @@ import android.hardware.display.DisplayManagerGlobal;
import android.os.IBinder;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.window.ActivityWindowInfo;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.concurrent.RejectedExecutionException;
import java.util.function.BiConsumer;
/**
@@ -47,6 +49,8 @@ import java.util.function.BiConsumer;
*/
public class ClientTransactionListenerController {
+ private static final String TAG = "ClientTransactionListenerController";
+
private static ClientTransactionListenerController sController;
private final Object mLock = new Object();
@@ -179,10 +183,14 @@ public class ClientTransactionListenerController {
}
// Dispatch the display changed callbacks.
- final int displayCount = configUpdatedDisplayIds.size();
- for (int i = 0; i < displayCount; i++) {
- final int displayId = configUpdatedDisplayIds.valueAt(i);
- onDisplayChanged(displayId);
+ try {
+ final int displayCount = configUpdatedDisplayIds.size();
+ for (int i = 0; i < displayCount; i++) {
+ final int displayId = configUpdatedDisplayIds.valueAt(i);
+ onDisplayChanged(displayId);
+ }
+ } catch (RejectedExecutionException e) {
+ Log.w(TAG, "Failed to notify DisplayListener because the Handler is shutting down");
}
}
@@ -222,7 +230,11 @@ public class ClientTransactionListenerController {
}
if (changedDisplayId != INVALID_DISPLAY) {
- onDisplayChanged(changedDisplayId);
+ try {
+ onDisplayChanged(changedDisplayId);
+ } catch (RejectedExecutionException e) {
+ Log.w(TAG, "Failed to notify DisplayListener because the Handler is shutting down");
+ }
}
}
@@ -235,9 +247,11 @@ public class ClientTransactionListenerController {
/**
* Called when receives a {@link Configuration} changed event that is updating display-related
* window configuration.
+ *
+ * @throws RejectedExecutionException if the display listener handler is closing.
*/
@VisibleForTesting
- public void onDisplayChanged(int displayId) {
+ public void onDisplayChanged(int displayId) throws RejectedExecutionException {
mDisplayManager.handleDisplayChangeFromWindowManager(displayId);
}
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9e316a2d3560..c8cae822570e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4353,13 +4353,6 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.extra.BRIGHTNESS_DIALOG_IS_FULL_WIDTH";
/**
- * Activity Action: Shows the contrast setting dialog.
- * @hide
- */
- public static final String ACTION_SHOW_CONTRAST_DIALOG =
- "com.android.intent.action.SHOW_CONTRAST_DIALOG";
-
- /**
* Broadcast Action: A global button was pressed. Includes a single
* extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that
* caused the broadcast.
diff --git a/core/java/android/content/TEST_MAPPING b/core/java/android/content/TEST_MAPPING
index f08395ae5e40..41a4288eae5c 100644
--- a/core/java/android/content/TEST_MAPPING
+++ b/core/java/android/content/TEST_MAPPING
@@ -56,6 +56,10 @@
}
],
"file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
+ },
+ {
+ "name": "CtsWindowManagerBackgroundActivityTestCases",
+ "file_patterns": ["(/|^)IntentSender.java"]
}
],
"ravenwood-presubmit": [
@@ -65,9 +69,5 @@
}
],
"postsubmit": [
- {
- "name": "CtsWindowManagerBackgroundActivityTestCases",
- "file_patterns": ["(/|^)IntentSender.java"]
- }
]
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 83285e0b8e8b..c506c9741635 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -270,11 +270,20 @@ public abstract class PackageManager {
/**
* Application level {@link android.content.pm.PackageManager.Property PackageManager
* .Property} for a app to inform the installer that a file containing the app's android
- * safety label data is bundled into the APK at the given path.
+ * safety label data is bundled into the APK as a raw resource.
+ *
+ * <p>For example:
+ * <pre>
+ * &lt;application&gt;
+ * &lt;property
+ * android:name="android.content.PROPERTY_ANDROID_SAFETY_LABEL"
+ * android:resource="@raw/app-metadata"/&gt;
+ * &lt;/application&gt;
+ * </pre>
* @hide
*/
- public static final String PROPERTY_ANDROID_SAFETY_LABEL_PATH =
- "android.content.SAFETY_LABEL_PATH";
+ public static final String PROPERTY_ANDROID_SAFETY_LABEL =
+ "android.content.PROPERTY_ANDROID_SAFETY_LABEL";
/**
* A property value set within the manifest.
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 83742eb7ae84..e2a131c0d527 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -247,3 +247,13 @@ flag {
description: "Allow MAIN user to access blocked number provider"
bug: "338579331"
}
+
+flag {
+ name: "restrict_quiet_mode_credential_bug_fix_to_managed_profiles"
+ namespace: "profile_experiences"
+ description: "Use user states to check the state of quiet mode for managed profiles only"
+ bug: "332812630"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index d683d72f17be..1eb466cb10a3 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -731,6 +731,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
* commits, or is rolled back, either explicitly or by a call to
* {@link #yieldIfContendedSafely}.
*/
+ // TODO(340874899) Provide an Executor overload
public void beginTransactionWithListener(
@Nullable SQLiteTransactionListener transactionListener) {
beginTransaction(transactionListener, true);
@@ -760,6 +761,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
* transaction begins, commits, or is rolled back, either
* explicitly or by a call to {@link #yieldIfContendedSafely}.
*/
+ // TODO(340874899) Provide an Executor overload
public void beginTransactionWithListenerNonExclusive(
@Nullable SQLiteTransactionListener transactionListener) {
beginTransaction(transactionListener, false);
@@ -785,6 +787,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
* }
* </pre>
*/
+ // TODO(340874899) Provide an Executor overload
+ @SuppressLint("ExecutorRegistration")
@FlaggedApi(Flags.FLAG_SQLITE_APIS_35)
public void beginTransactionWithListenerReadOnly(
@Nullable SQLiteTransactionListener transactionListener) {
diff --git a/core/java/android/hardware/usb/DeviceFilter.java b/core/java/android/hardware/usb/DeviceFilter.java
index 66b0a426f35d..3a271b44eef2 100644
--- a/core/java/android/hardware/usb/DeviceFilter.java
+++ b/core/java/android/hardware/usb/DeviceFilter.java
@@ -18,6 +18,7 @@ package android.hardware.usb;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.usb.flags.Flags;
import android.service.usb.UsbDeviceFilterProto;
import android.util.Slog;
@@ -57,9 +58,12 @@ public class DeviceFilter {
public final String mProductName;
// USB device serial number string (or null for unspecified)
public final String mSerialNumber;
+ // USB interface name (or null for unspecified). This will be used when matching devices using
+ // the available interfaces.
+ public final String mInterfaceName;
public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
- String manufacturer, String product, String serialnum) {
+ String manufacturer, String product, String serialnum, String interfaceName) {
mVendorId = vid;
mProductId = pid;
mClass = clasz;
@@ -68,6 +72,7 @@ public class DeviceFilter {
mManufacturerName = manufacturer;
mProductName = product;
mSerialNumber = serialnum;
+ mInterfaceName = interfaceName;
}
public DeviceFilter(UsbDevice device) {
@@ -79,6 +84,7 @@ public class DeviceFilter {
mManufacturerName = device.getManufacturerName();
mProductName = device.getProductName();
mSerialNumber = device.getSerialNumber();
+ mInterfaceName = null;
}
public DeviceFilter(@NonNull DeviceFilter filter) {
@@ -90,6 +96,7 @@ public class DeviceFilter {
mManufacturerName = filter.mManufacturerName;
mProductName = filter.mProductName;
mSerialNumber = filter.mSerialNumber;
+ mInterfaceName = filter.mInterfaceName;
}
public static DeviceFilter read(XmlPullParser parser)
@@ -102,7 +109,7 @@ public class DeviceFilter {
String manufacturerName = null;
String productName = null;
String serialNumber = null;
-
+ String interfaceName = null;
int count = parser.getAttributeCount();
for (int i = 0; i < count; i++) {
String name = parser.getAttributeName(i);
@@ -114,6 +121,8 @@ public class DeviceFilter {
productName = value;
} else if ("serial-number".equals(name)) {
serialNumber = value;
+ } else if ("interface-name".equals(name)) {
+ interfaceName = value;
} else {
int intValue;
int radix = 10;
@@ -144,7 +153,7 @@ public class DeviceFilter {
}
return new DeviceFilter(vendorId, productId,
deviceClass, deviceSubclass, deviceProtocol,
- manufacturerName, productName, serialNumber);
+ manufacturerName, productName, serialNumber, interfaceName);
}
public void write(XmlSerializer serializer) throws IOException {
@@ -173,13 +182,25 @@ public class DeviceFilter {
if (mSerialNumber != null) {
serializer.attribute(null, "serial-number", mSerialNumber);
}
+ if (mInterfaceName != null) {
+ serializer.attribute(null, "interface-name", mInterfaceName);
+ }
serializer.endTag(null, "usb-device");
}
- private boolean matches(int clasz, int subclass, int protocol) {
- return ((mClass == -1 || clasz == mClass) &&
- (mSubclass == -1 || subclass == mSubclass) &&
- (mProtocol == -1 || protocol == mProtocol));
+ private boolean matches(int usbClass, int subclass, int protocol) {
+ return ((mClass == -1 || usbClass == mClass)
+ && (mSubclass == -1 || subclass == mSubclass)
+ && (mProtocol == -1 || protocol == mProtocol));
+ }
+
+ private boolean matches(int usbClass, int subclass, int protocol, String interfaceName) {
+ if (Flags.enableInterfaceNameDeviceFilter()) {
+ return matches(usbClass, subclass, protocol)
+ && (mInterfaceName == null || mInterfaceName.equals(interfaceName));
+ } else {
+ return matches(usbClass, subclass, protocol);
+ }
}
public boolean matches(UsbDevice device) {
@@ -204,7 +225,7 @@ public class DeviceFilter {
for (int i = 0; i < count; i++) {
UsbInterface intf = device.getInterface(i);
if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
- intf.getInterfaceProtocol())) return true;
+ intf.getInterfaceProtocol(), intf.getName())) return true;
}
return false;
@@ -320,11 +341,12 @@ public class DeviceFilter {
@Override
public String toString() {
- return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
- ",mClass=" + mClass + ",mSubclass=" + mSubclass +
- ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName +
- ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber +
- "]";
+ return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId
+ + ",mClass=" + mClass + ",mSubclass=" + mSubclass
+ + ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName
+ + ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber
+ + ",mInterfaceName=" + mInterfaceName
+ + "]";
}
/**
diff --git a/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig b/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
index 94df16030cdb..40e5ffb141ab 100644
--- a/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
+++ b/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
@@ -16,3 +16,11 @@ flag {
description: "Feature flag for the api to check if a port supports mode change"
bug: "323470419"
}
+
+flag {
+ name: "enable_interface_name_device_filter"
+ is_exported: true
+ namespace: "usb"
+ description: "Feature flag to enable interface name as a parameter for device filter"
+ bug: "312828160"
+}
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
index 8237b20260ea..144c1cda3470 100644
--- a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
@@ -120,6 +120,11 @@ public abstract class OnDeviceSandboxedInferenceService extends Service {
*/
public static final String MODEL_UNLOADED_BUNDLE_KEY = "model_unloaded";
+ /**
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_UPDATE_BUNDLE_KEY = "device_config_update";
+
private IRemoteStorageService mRemoteStorageService;
/**
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 35b137a322e3..c5b6aa7118cb 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -129,7 +129,7 @@ public class FocusFinder {
}
ViewGroup effective = null;
ViewParent nextParent = focused.getParent();
- do {
+ while (nextParent instanceof ViewGroup) {
if (nextParent == root) {
return effective != null ? effective : root;
}
@@ -143,7 +143,7 @@ public class FocusFinder {
effective = vg;
}
nextParent = nextParent.getParent();
- } while (nextParent instanceof ViewGroup);
+ }
return root;
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index f1cb4103f008..d7f2b01f46ea 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1262,10 +1262,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
mHost.getInputMethodManager(), null /* icProto */);
}
+ final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_USER,
+ ImeTracker.ORIGIN_CLIENT, SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION,
+ mHost.isHandlingPointerEvent() /* fromUser */);
controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
interpolator, animationType,
getLayoutInsetsDuringAnimationMode(types, fromPredictiveBack),
- false /* useInsetsAnimationThread */, null /* statsToken */);
+ false /* useInsetsAnimationThread */, statsToken);
}
private void controlAnimationUnchecked(@InsetsType int types,
@@ -1567,7 +1570,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
return;
}
final ImeTracker.Token statsToken = runner.getStatsToken();
- if (shown) {
+ if (runner.getAnimationType() == ANIMATION_TYPE_USER) {
+ ImeTracker.forLogging().onUserFinished(statsToken, shown);
+ } else if (shown) {
ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_CLIENT_ANIMATION_FINISHED_SHOW);
ImeTracker.forLogging().onShown(statsToken);
@@ -1838,6 +1843,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.pendingAnim", 0);
mHost.dispatchWindowInsetsAnimationStart(animation, bounds);
mStartingAnimation = true;
+ if (runner.getAnimationType() == ANIMATION_TYPE_USER) {
+ ImeTracker.forLogging().onDispatched(runner.getStatsToken());
+ }
runner.setReadyDispatched(true);
listener.onReady(runner, types);
mStartingAnimation = false;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1df851a29b07..0715474f1c13 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -921,15 +921,6 @@ public final class ViewRootImpl implements ViewParent,
private String mFrameRateCategoryView;
/**
- * The resolved pointer icon type requested by this window.
- * A null value indicates the resolved pointer icon has not yet been calculated.
- */
- // TODO(b/293587049): Remove pointer icon tracking by type when refactor is complete.
- @Nullable
- private Integer mPointerIconType = null;
- private PointerIcon mCustomPointerIcon = null;
-
- /**
* The resolved pointer icon requested by this window.
* A null value indicates the resolved pointer icon has not yet been calculated.
*/
@@ -6430,7 +6421,6 @@ public final class ViewRootImpl implements ViewParent,
private static final int MSG_SYNTHESIZE_INPUT_EVENT = 24;
private static final int MSG_DISPATCH_WINDOW_SHOWN = 25;
private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
- private static final int MSG_UPDATE_POINTER_ICON = 27;
private static final int MSG_POINTER_CAPTURE_CHANGED = 28;
private static final int MSG_INSETS_CONTROL_CHANGED = 29;
private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 30;
@@ -6495,8 +6485,6 @@ public final class ViewRootImpl implements ViewParent,
return "MSG_SYNTHESIZE_INPUT_EVENT";
case MSG_DISPATCH_WINDOW_SHOWN:
return "MSG_DISPATCH_WINDOW_SHOWN";
- case MSG_UPDATE_POINTER_ICON:
- return "MSG_UPDATE_POINTER_ICON";
case MSG_POINTER_CAPTURE_CHANGED:
return "MSG_POINTER_CAPTURE_CHANGED";
case MSG_INSETS_CONTROL_CHANGED:
@@ -6747,10 +6735,6 @@ public final class ViewRootImpl implements ViewParent,
final int deviceId = msg.arg1;
handleRequestKeyboardShortcuts(receiver, deviceId);
} break;
- case MSG_UPDATE_POINTER_ICON: {
- MotionEvent event = (MotionEvent) msg.obj;
- resetPointerIcon(event);
- } break;
case MSG_POINTER_CAPTURE_CHANGED: {
final boolean hasCapture = msg.arg1 != 0;
handlePointerCaptureChanged(hasCapture);
@@ -7836,14 +7820,12 @@ public final class ViewRootImpl implements ViewParent,
|| action == MotionEvent.ACTION_HOVER_EXIT) {
// Other apps or the window manager may change the icon type outside of
// this app, therefore the icon type has to be reset on enter/exit event.
- mPointerIconType = null;
mResolvedPointerIcon = null;
}
if (action != MotionEvent.ACTION_HOVER_EXIT) {
// Resolve the pointer icon
if (!updatePointerIcon(event) && action == MotionEvent.ACTION_HOVER_MOVE) {
- mPointerIconType = null;
mResolvedPointerIcon = null;
}
}
@@ -7906,12 +7888,6 @@ public final class ViewRootImpl implements ViewParent,
return mAttachInfo.mHandlingPointerEvent;
}
- private void resetPointerIcon(MotionEvent event) {
- mPointerIconType = null;
- mResolvedPointerIcon = null;
- updatePointerIcon(event);
- }
-
/**
* If there is pointer that is showing a PointerIcon in this window, refresh the icon for that
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
index f454a6abf6a0..3091bf48a09e 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
@@ -754,6 +754,19 @@ final class IInputMethodManagerGlobalInvoker {
}
}
+ /** @see com.android.server.inputmethod.ImeTrackerService#onDispatched */
+ static void onDispatched(@NonNull ImeTracker.Token statsToken) {
+ final IImeTracker service = getImeTrackerService();
+ if (service == null) {
+ return;
+ }
+ try {
+ service.onDispatched(statsToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @see com.android.server.inputmethod.ImeTrackerService#hasPendingImeVisibilityRequests */
@AnyThread
@RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index d992febc375e..edc99218c71e 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -71,24 +71,40 @@ public interface ImeTracker {
/** The type of the IME request. */
@IntDef(prefix = { "TYPE_" }, value = {
TYPE_SHOW,
- TYPE_HIDE
+ TYPE_HIDE,
+ TYPE_USER,
})
@Retention(RetentionPolicy.SOURCE)
@interface Type {}
- /** IME show request type. */
+ /**
+ * IME show request type.
+ *
+ * @see android.view.InsetsController#ANIMATION_TYPE_SHOW
+ */
int TYPE_SHOW = ImeProtoEnums.TYPE_SHOW;
- /** IME hide request type. */
+ /**
+ * IME hide request type.
+ *
+ * @see android.view.InsetsController#ANIMATION_TYPE_HIDE
+ */
int TYPE_HIDE = ImeProtoEnums.TYPE_HIDE;
+ /**
+ * IME user-controlled animation request type.
+ *
+ * @see android.view.InsetsController#ANIMATION_TYPE_USER
+ */
+ int TYPE_USER = ImeProtoEnums.TYPE_USER;
+
/** The status of the IME request. */
@IntDef(prefix = { "STATUS_" }, value = {
STATUS_RUN,
STATUS_CANCEL,
STATUS_FAIL,
STATUS_SUCCESS,
- STATUS_TIMEOUT
+ STATUS_TIMEOUT,
})
@Retention(RetentionPolicy.SOURCE)
@interface Status {}
@@ -117,7 +133,7 @@ public interface ImeTracker {
@IntDef(prefix = { "ORIGIN_" }, value = {
ORIGIN_CLIENT,
ORIGIN_SERVER,
- ORIGIN_IME
+ ORIGIN_IME,
})
@Retention(RetentionPolicy.SOURCE)
@interface Origin {}
@@ -400,20 +416,36 @@ public interface ImeTracker {
void onCancelled(@Nullable Token token, @Phase int phase);
/**
- * Called when the IME show request is successful.
+ * Called when the show IME request is successful.
*
* @param token the token tracking the current IME request or {@code null} otherwise.
*/
void onShown(@Nullable Token token);
/**
- * Called when the IME hide request is successful.
+ * Called when the hide IME request is successful.
*
* @param token the token tracking the current IME request or {@code null} otherwise.
*/
void onHidden(@Nullable Token token);
/**
+ * Called when the user-controlled IME request was dispatched to the requesting app. The
+ * user animation can take an undetermined amount of time, so it shouldn't be tracked.
+ *
+ * @param token the token tracking the current IME request or {@code null} otherwise.
+ */
+ void onDispatched(@Nullable Token token);
+
+ /**
+ * Called when the animation of the user-controlled IME request finished.
+ *
+ * @param token the token tracking the current IME request or {@code null} otherwise.
+ * @param shown whether the end state of the animation was shown or hidden.
+ */
+ void onUserFinished(@Nullable Token token, boolean shown);
+
+ /**
* Returns whether the current IME request was created due to a user interaction. This can
* only be {@code true} when running on the view's UI thread.
*
@@ -482,13 +514,6 @@ public interface ImeTracker {
/** Whether the stack trace at the request call site should be logged. */
private boolean mLogStackTrace;
- private void reloadSystemProperties() {
- mLogProgress = SystemProperties.getBoolean(
- "persist.debug.imetracker", false);
- mLogStackTrace = SystemProperties.getBoolean(
- "persist.debug.imerequest.logstacktrace", false);
- }
-
@NonNull
@Override
public Token onStart(@NonNull String component, int uid, @Type int type, @Origin int origin,
@@ -497,7 +522,7 @@ public interface ImeTracker {
final var token = IInputMethodManagerGlobalInvoker.onStart(tag, uid, type,
origin, reason, fromUser);
- Log.i(TAG, token.mTag + ": onRequest" + (type == TYPE_SHOW ? "Show" : "Hide")
+ Log.i(TAG, token.mTag + ": " + getOnStartPrefix(type)
+ " at " + Debug.originToString(origin)
+ " reason " + InputMethodDebug.softInputDisplayReasonToString(reason)
+ " fromUser " + fromUser,
@@ -552,6 +577,45 @@ public interface ImeTracker {
Log.i(TAG, token.mTag + ": onHidden");
}
+
+ @Override
+ public void onDispatched(@Nullable Token token) {
+ if (token == null) return;
+ IInputMethodManagerGlobalInvoker.onDispatched(token);
+
+ Log.i(TAG, token.mTag + ": onDispatched");
+ }
+
+ @Override
+ public void onUserFinished(@Nullable Token token, boolean shown) {
+ if (token == null) return;
+ // This is already sent to ImeTrackerService to mark it finished during onDispatched.
+
+ Log.i(TAG, token.mTag + ": onUserFinished " + (shown ? "shown" : "hidden"));
+ }
+
+ /**
+ * Gets the prefix string for {@link #onStart} based on the given request type.
+ *
+ * @param type request type for which to create the prefix string with.
+ */
+ @NonNull
+ private static String getOnStartPrefix(@Type int type) {
+ return switch (type) {
+ case TYPE_SHOW -> "onRequestShow";
+ case TYPE_HIDE -> "onRequestHide";
+ case TYPE_USER -> "onRequestUser";
+ default -> "onRequestUnknown";
+ };
+ }
+
+ /** Reloads the system properties related to this class. */
+ private void reloadSystemProperties() {
+ mLogProgress = SystemProperties.getBoolean(
+ "persist.debug.imetracker", false);
+ mLogStackTrace = SystemProperties.getBoolean(
+ "persist.debug.imerequest.logstacktrace", false);
+ }
};
/** The singleton IME tracker instance for instrumenting jank metrics. */
diff --git a/core/java/android/window/TaskFragmentParentInfo.java b/core/java/android/window/TaskFragmentParentInfo.java
index a77c23475c60..15554167c702 100644
--- a/core/java/android/window/TaskFragmentParentInfo.java
+++ b/core/java/android/window/TaskFragmentParentInfo.java
@@ -18,6 +18,8 @@ package android.window;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.os.Parcel;
@@ -27,10 +29,13 @@ import android.view.SurfaceControl;
import java.util.Objects;
/**
- * The information about the parent Task of a particular TaskFragment
+ * The information about the parent Task of a particular TaskFragment.
+ *
* @hide
*/
-public class TaskFragmentParentInfo implements Parcelable {
+@SuppressLint("UnflaggedApi") // @TestApi to replace legacy usages.
+@TestApi
+public final class TaskFragmentParentInfo implements Parcelable {
@NonNull
private final Configuration mConfiguration = new Configuration();
@@ -42,6 +47,7 @@ public class TaskFragmentParentInfo implements Parcelable {
@Nullable private final SurfaceControl mDecorSurface;
+ /** @hide */
public TaskFragmentParentInfo(@NonNull Configuration configuration, int displayId,
boolean visible, boolean hasDirectActivity, @Nullable SurfaceControl decorSurface) {
mConfiguration.setTo(configuration);
@@ -51,6 +57,7 @@ public class TaskFragmentParentInfo implements Parcelable {
mDecorSurface = decorSurface;
}
+ /** @hide */
public TaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
mConfiguration.setTo(info.getConfiguration());
mDisplayId = info.mDisplayId;
@@ -59,7 +66,11 @@ public class TaskFragmentParentInfo implements Parcelable {
mDecorSurface = info.mDecorSurface;
}
- /** The {@link Configuration} of the parent Task */
+ /**
+ * The {@link Configuration} of the parent Task
+ *
+ * @hide
+ */
@NonNull
public Configuration getConfiguration() {
return mConfiguration;
@@ -68,19 +79,27 @@ public class TaskFragmentParentInfo implements Parcelable {
/**
* The display ID of the parent Task. {@link android.view.Display#INVALID_DISPLAY} means the
* Task is detached from previously associated display.
+ *
+ * @hide
*/
public int getDisplayId() {
return mDisplayId;
}
- /** Whether the parent Task is visible or not */
+ /**
+ * Whether the parent Task is visible or not
+ *
+ * @hide
+ */
public boolean isVisible() {
return mVisible;
}
/**
* Whether the parent Task has any direct child activity, which is not embedded in any
- * TaskFragment, or not
+ * TaskFragment, or not.
+ *
+ * @hide
*/
public boolean hasDirectActivity() {
return mHasDirectActivity;
@@ -93,6 +112,8 @@ public class TaskFragmentParentInfo implements Parcelable {
* {@link com.android.server.wm.WindowOrganizerController#configurationsAreEqualForOrganizer(
* Configuration, Configuration)} to determine if this {@link TaskFragmentParentInfo} should
* be dispatched to the client.
+ *
+ * @hide
*/
public boolean equalsForTaskFragmentOrganizer(@Nullable TaskFragmentParentInfo that) {
if (that == null) {
@@ -103,6 +124,7 @@ public class TaskFragmentParentInfo implements Parcelable {
&& mDecorSurface == that.mDecorSurface;
}
+ /** @hide */
@Nullable
public SurfaceControl getDecorSurface() {
return mDecorSurface;
@@ -156,6 +178,7 @@ public class TaskFragmentParentInfo implements Parcelable {
return result;
}
+ @SuppressLint("UnflaggedApi") // @TestApi to replace legacy usages.
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
mConfiguration.writeToParcel(dest, flags);
@@ -173,6 +196,8 @@ public class TaskFragmentParentInfo implements Parcelable {
mDecorSurface = in.readTypedObject(SurfaceControl.CREATOR);
}
+ @SuppressLint("UnflaggedApi") // @TestApi to replace legacy usages.
+ @NonNull
public static final Creator<TaskFragmentParentInfo> CREATOR =
new Creator<TaskFragmentParentInfo>() {
@Override
@@ -186,6 +211,7 @@ public class TaskFragmentParentInfo implements Parcelable {
}
};
+ @SuppressLint("UnflaggedApi") // @TestApi to replace legacy usages.
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java
index 4dada108c4c6..32e3f5ad10ca 100644
--- a/core/java/android/window/TaskFragmentTransaction.java
+++ b/core/java/android/window/TaskFragmentTransaction.java
@@ -24,7 +24,6 @@ import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.content.Intent;
-import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -248,13 +247,6 @@ public final class TaskFragmentTransaction implements Parcelable {
return this;
}
- // TODO(b/241043377): Keep this API to prevent @TestApi changes. Remove in the next release.
- /** Configuration of the parent Task. */
- @NonNull
- public Change setTaskConfiguration(@NonNull Configuration configuration) {
- return this;
- }
-
/**
* If the {@link #TYPE_TASK_FRAGMENT_ERROR} is from a {@link WindowContainerTransaction}
* from the {@link TaskFragmentOrganizer}, it may come with an error callback token to
@@ -299,12 +291,11 @@ public final class TaskFragmentTransaction implements Parcelable {
return this;
}
- // TODO(b/241043377): Hide this API to prevent @TestApi changes. Remove in the next release.
/**
* Sets info of the parent Task of the embedded TaskFragment.
* @see TaskFragmentParentInfo
*
- * @hide pending unhide
+ * @hide
*/
@NonNull
public Change setTaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
@@ -338,12 +329,6 @@ public final class TaskFragmentTransaction implements Parcelable {
return mTaskId;
}
- // TODO(b/241043377): Keep this API to prevent @TestApi changes. Remove in the next release.
- @Nullable
- public Configuration getTaskConfiguration() {
- return mTaskFragmentParentInfo.getConfiguration();
- }
-
@Nullable
public IBinder getErrorCallbackToken() {
return mErrorCallbackToken;
@@ -365,8 +350,10 @@ public final class TaskFragmentTransaction implements Parcelable {
return mActivityToken;
}
- // TODO(b/241043377): Hide this API to prevent @TestApi changes. Remove in the next release.
- /** @hide pending unhide */
+ /**
+ * Obtains the {@link TaskFragmentParentInfo} for this transaction.
+ */
+ @SuppressLint("UnflaggedApi") // @TestApi to replace legacy usages.
@Nullable
public TaskFragmentParentInfo getTaskFragmentParentInfo() {
return mTaskFragmentParentInfo;
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index cd13c4abac0b..4b2beb903325 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -9,6 +9,16 @@ flag {
}
flag {
+ name: "disable_thin_letterboxing_policy"
+ namespace: "large_screen_experiences_app_compat"
+ description: "Whether reachability is disabled in case of thin letterboxing"
+ bug: "341027847"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "allows_screen_size_decoupled_from_status_bar_and_cutout"
namespace: "large_screen_experiences_app_compat"
description: "When necessary, configuration decoupled from status bar and display cutout"
diff --git a/core/java/com/android/internal/inputmethod/IImeTracker.aidl b/core/java/com/android/internal/inputmethod/IImeTracker.aidl
index ab4edb65780b..ebae39ee3241 100644
--- a/core/java/com/android/internal/inputmethod/IImeTracker.aidl
+++ b/core/java/com/android/internal/inputmethod/IImeTracker.aidl
@@ -64,20 +64,28 @@ interface IImeTracker {
oneway void onCancelled(in ImeTracker.Token statsToken, int phase);
/**
- * Called when the IME show request is successful.
+ * Called when the show IME request is successful.
*
* @param statsToken the token tracking the current IME request.
*/
oneway void onShown(in ImeTracker.Token statsToken);
/**
- * Called when the IME hide request is successful.
+ * Called when the hide IME request is successful.
*
* @param statsToken the token tracking the current IME request.
*/
oneway void onHidden(in ImeTracker.Token statsToken);
/**
+ * Called when the user-controlled IME request was dispatched to the requesting app. The
+ * user animation can take an undetermined amount of time, so it shouldn't be tracked.
+ *
+ * @param statsToken the token tracking the current IME request.
+ */
+ oneway void onDispatched(in ImeTracker.Token statsToken);
+
+ /**
* Checks whether there are any pending IME visibility requests.
*
* @return {@code true} iff there are pending IME visibility requests.
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index a0aad31d2e04..2a5593f6d584 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -297,6 +297,8 @@ public final class InputMethodDebug {
return "SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT";
case SoftInputShowHideReason.SHOW_SOFT_INPUT_IMM_DEPRECATION:
return "SHOW_SOFT_INPUT_IMM_DEPRECATION";
+ case SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION:
+ return "CONTROL_WINDOW_INSETS_ANIMATION";
default:
return "Unknown=" + reason;
}
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index da738a01ec39..eb6a81031321 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -88,6 +88,7 @@ import java.lang.annotation.Retention;
SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL,
SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT,
SoftInputShowHideReason.SHOW_SOFT_INPUT_IMM_DEPRECATION,
+ SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION,
})
public @interface SoftInputShowHideReason {
/** Default, undefined reason. */
@@ -397,4 +398,10 @@ public @interface SoftInputShowHideReason {
* {@link InputMethodManager#showSoftInputFromInputMethod(IBinder, int)}.
*/
int SHOW_SOFT_INPUT_IMM_DEPRECATION = ImeProtoEnums.REASON_SHOW_SOFT_INPUT_IMM_DEPRECATION;
+
+ /**
+ * Show / Hide soft input by application-controlled animation in
+ * {@link android.view.InsetsController#controlWindowInsetsAnimation}.
+ */
+ int CONTROL_WINDOW_INSETS_ANIMATION = ImeProtoEnums.REASON_CONTROL_WINDOW_INSETS_ANIMATION;
}
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index 97ce96ec30f6..1dcd893eb143 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -1908,12 +1908,16 @@ public class ParsingPackageUtils {
} else if (parser.getName().equals("package")) {
final TypedArray sa = res.obtainAttributes(parser,
R.styleable.AndroidManifestQueriesPackage);
- final String packageName = sa.getNonConfigurationString(
- R.styleable.AndroidManifestQueriesPackage_name, 0);
- if (TextUtils.isEmpty(packageName)) {
- return input.error("Package name is missing from package tag.");
+ try {
+ final String packageName = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestQueriesPackage_name, 0);
+ if (TextUtils.isEmpty(packageName)) {
+ return input.error("Package name is missing from package tag.");
+ }
+ pkg.addQueriesPackage(packageName.intern());
+ } finally {
+ sa.recycle();
}
- pkg.addQueriesPackage(packageName.intern());
} else if (parser.getName().equals("provider")) {
final TypedArray sa = res.obtainAttributes(parser,
R.styleable.AndroidManifestQueriesProvider);
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5bd20332f381..f5b45660c547 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4723,6 +4723,8 @@
<!-- The broadcast intent name for notifying when the on-device model has been unloaded -->
<string name="config_onDeviceIntelligenceModelUnloadedBroadcastKey" translatable="false"></string>
+ <!-- The DeviceConfig namespace for the default system on-device sandboxed inference service. -->
+ <string name="config_defaultOnDeviceIntelligenceDeviceConfigNamespace" translatable="false"></string>
<!-- Component name that accepts ACTION_SEND intents for requesting ambient context consent for
wearable sensing. -->
diff --git a/core/res/res/values/config_battery_stats.xml b/core/res/res/values/config_battery_stats.xml
index 8d9736273145..80cf0881e8cc 100644
--- a/core/res/res/values/config_battery_stats.xml
+++ b/core/res/res/values/config_battery_stats.xml
@@ -27,16 +27,18 @@
<!-- Whether to reset Battery Stats on unplug if the battery was significantly charged -->
<bool name="config_batteryStatsResetOnUnplugAfterSignificantCharge">true</bool>
- <!-- CPU power stats collection throttle period in milliseconds. Since power stats collection
- is a relatively expensive operation, this throttle period may need to be adjusted for low-power
- devices-->
- <integer name="config_defaultPowerStatsThrottlePeriodCpu">60000</integer>
-
- <!-- Mobile Radio power stats collection throttle period in milliseconds. -->
- <integer name="config_defaultPowerStatsThrottlePeriodMobileRadio">3600000</integer>
-
- <!-- Mobile Radio power stats collection throttle period in milliseconds. -->
- <integer name="config_defaultPowerStatsThrottlePeriodWifi">3600000</integer>
+ <!-- Power stats collection throttle periods in milliseconds. Since power stats collection
+ is a relatively expensive operation, these throttle period may need to be adjusted for low-power
+ devices.
+
+ The syntax of this config string is as follows:
+ <pre>
+ power-component-name1:throttle-period-millis1 power-component-name2:throttle-period-ms2 ...
+ </pre>
+ Use "*" for the power-component-name to represent the default for all power components
+ not mentioned by name.
+ -->
+ <string name="config_powerStatsThrottlePeriods">cpu:60000 *:300000</string>
<!-- PowerStats aggregation period in milliseconds. This is the interval at which the power
stats aggregation procedure is performed and the results stored in PowerStatsStore. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a9d03f543d55..a6bb8d7e28e1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3947,6 +3947,7 @@
<java-symbol type="string" name="config_defaultOnDeviceSandboxedInferenceService" />
<java-symbol type="string" name="config_onDeviceIntelligenceModelLoadedBroadcastKey" />
<java-symbol type="string" name="config_onDeviceIntelligenceModelUnloadedBroadcastKey" />
+ <java-symbol type="string" name="config_defaultOnDeviceIntelligenceDeviceConfigNamespace" />
<java-symbol type="string" name="config_retailDemoPackage" />
<java-symbol type="string" name="config_retailDemoPackageSignature" />
@@ -5243,9 +5244,7 @@
<java-symbol type="bool" name="config_batteryStatsResetOnUnplugHighBatteryLevel" />
<java-symbol type="bool" name="config_batteryStatsResetOnUnplugAfterSignificantCharge" />
- <java-symbol type="integer" name="config_defaultPowerStatsThrottlePeriodCpu" />
- <java-symbol type="integer" name="config_defaultPowerStatsThrottlePeriodMobileRadio" />
- <java-symbol type="integer" name="config_defaultPowerStatsThrottlePeriodWifi" />
+ <java-symbol type="string" name="config_powerStatsThrottlePeriods" />
<java-symbol type="integer" name="config_powerStatsAggregationPeriod" />
<java-symbol type="integer" name="config_aggregatedPowerStatsSpanDuration" />
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
index b6f4429aec8a..ee1d1e1b975c 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
@@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -65,6 +66,7 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.RejectedExecutionException;
import java.util.function.BiConsumer;
/**
@@ -221,4 +223,17 @@ public class ClientTransactionListenerControllerTest {
123 /* newDisplayId */, true /* shouldReportConfigChange*/);
inOrder.verify(mController).onContextConfigurationPostChanged(context);
}
+
+ @Test
+ public void testDisplayListenerHandlerClosed() {
+ doReturn(123).when(mActivity).getDisplayId();
+ doThrow(new RejectedExecutionException()).when(mController).onDisplayChanged(123);
+
+ mController.onContextConfigurationPreChanged(mActivity);
+ mConfiguration.windowConfiguration.setMaxBounds(new Rect(0, 0, 100, 200));
+ mController.onContextConfigurationPostChanged(mActivity);
+
+ // No crash
+ verify(mController).onDisplayChanged(123);
+ }
}
diff --git a/data/etc/core.protolog.pb b/data/etc/core.protolog.pb
index 000f6ef46c2c..b41a607e91c7 100644
--- a/data/etc/core.protolog.pb
+++ b/data/etc/core.protolog.pb
Binary files differ
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 01deb4957cd3..b93cd468118a 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -583,6 +583,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "7211222997110112110": {
+ "message": "Refreshing activity for freeform camera compatibility treatment, activityRecord=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRefresher.java"
+ },
"1665699123574159131": {
"message": "Starting activity when config will change = %b",
"level": "VERBOSE",
@@ -1771,12 +1777,6 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
},
- "-7756685416834187936": {
- "message": "Refreshing activity for camera compatibility treatment, activityRecord=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_STATES",
- "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
- },
"-5176775281239247368": {
"message": "Reverting orientation after camera compat force rotation",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 9284c0e5b928..4bc3ecebb067 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -2493,7 +2493,11 @@ public abstract class ColorSpace {
return mNativePtr;
}
- /** Need a nested class due to b/337329128. */
+ /**
+ * These methods can't be put in the Rgb class directly, because ColorSpace's
+ * static initializer instantiates Rgb, whose constructor needs them, which is a variation
+ * of b/337329128.
+ */
static class Native {
static native long nativeGetNativeFinalizer();
static native long nativeCreate(float a, float b, float c, float d,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
index 1fbaeeac8608..29936cc2cac3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
@@ -33,7 +33,9 @@ import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSI
import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_RIGHT;
import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_TOP;
-import android.annotation.DimenRes;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityThread;
@@ -53,9 +55,11 @@ import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
+import android.view.VelocityTracker;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
+import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.window.InputTransferToken;
@@ -97,6 +101,16 @@ class DividerPresenter implements View.OnTouchListener {
@VisibleForTesting
static final int DEFAULT_DIVIDER_WIDTH_DP = 24;
+ @VisibleForTesting
+ static final PathInterpolator FLING_ANIMATION_INTERPOLATOR =
+ new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ @VisibleForTesting
+ static final int FLING_ANIMATION_DURATION = 250;
+ @VisibleForTesting
+ static final int MIN_DISMISS_VELOCITY_DP_PER_SECOND = 600;
+ @VisibleForTesting
+ static final int MIN_FLING_VELOCITY_DP_PER_SECOND = 400;
+
private final int mTaskId;
@NonNull
@@ -109,6 +123,14 @@ class DividerPresenter implements View.OnTouchListener {
private final Executor mCallbackExecutor;
/**
+ * The VelocityTracker of the divider, used to track the dragging velocity. This field is
+ * {@code null} until dragging starts.
+ */
+ @GuardedBy("mLock")
+ @Nullable
+ VelocityTracker mVelocityTracker;
+
+ /**
* The {@link Properties} of the divider. This field is {@code null} when no divider should be
* drawn, e.g. when the split doesn't have {@link DividerAttributes} or when the decor surface
* is not available.
@@ -370,13 +392,11 @@ class DividerPresenter implements View.OnTouchListener {
applicationContext.getResources().getDisplayMetrics());
}
- private static int getDimensionDp(@DimenRes int resId) {
- final Context context = ActivityThread.currentActivityThread().getApplication();
- final int px = context.getResources().getDimensionPixelSize(resId);
- return (int) TypedValue.convertPixelsToDimension(
- COMPLEX_UNIT_DIP,
- px,
- context.getResources().getDisplayMetrics());
+ private static float getDisplayDensity() {
+ // TODO(b/329193115) support divider on secondary display
+ final Context applicationContext =
+ ActivityThread.currentActivityThread().getApplication();
+ return applicationContext.getResources().getDisplayMetrics().density;
}
/**
@@ -487,24 +507,27 @@ class DividerPresenter implements View.OnTouchListener {
@Override
public boolean onTouch(@NonNull View view, @NonNull MotionEvent event) {
synchronized (mLock) {
- final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
- mDividerPosition = calculateDividerPosition(
- event, taskBounds, mRenderer.mDividerWidthPx, mProperties.mDividerAttributes,
- mProperties.mIsVerticalSplit, calculateMinPosition(), calculateMaxPosition());
- mRenderer.setDividerPosition(mDividerPosition);
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- onStartDragging();
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- onFinishDragging();
- break;
- case MotionEvent.ACTION_MOVE:
- onDrag();
- break;
- default:
- break;
+ if (mProperties != null && mRenderer != null) {
+ final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
+ mDividerPosition = calculateDividerPosition(
+ event, taskBounds, mRenderer.mDividerWidthPx,
+ mProperties.mDividerAttributes, mProperties.mIsVerticalSplit,
+ calculateMinPosition(), calculateMaxPosition());
+ mRenderer.setDividerPosition(mDividerPosition);
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ onStartDragging(event);
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ onFinishDragging(event);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ onDrag(event);
+ break;
+ default:
+ break;
+ }
}
}
@@ -514,7 +537,10 @@ class DividerPresenter implements View.OnTouchListener {
}
@GuardedBy("mLock")
- private void onStartDragging() {
+ private void onStartDragging(@NonNull MotionEvent event) {
+ mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker.addMovement(event);
+
mRenderer.mIsDragging = true;
mRenderer.mDragHandle.setPressed(mRenderer.mIsDragging);
mRenderer.updateSurface();
@@ -536,16 +562,81 @@ class DividerPresenter implements View.OnTouchListener {
}
@GuardedBy("mLock")
- private void onDrag() {
+ private void onDrag(@NonNull MotionEvent event) {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(event);
+ }
mRenderer.updateSurface();
}
@GuardedBy("mLock")
- private void onFinishDragging() {
- mDividerPosition = adjustDividerPositionForSnapPoints(mDividerPosition);
- mRenderer.setDividerPosition(mDividerPosition);
+ private void onFinishDragging(@NonNull MotionEvent event) {
+ float velocity = 0.0f;
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(event);
+ mVelocityTracker.computeCurrentVelocity(1000 /* units */);
+ velocity = mProperties.mIsVerticalSplit
+ ? mVelocityTracker.getXVelocity()
+ : mVelocityTracker.getYVelocity();
+ mVelocityTracker.recycle();
+ }
+
+ final int prevDividerPosition = mDividerPosition;
+ mDividerPosition = dividerPositionForSnapPoints(mDividerPosition, velocity);
+ if (mDividerPosition != prevDividerPosition) {
+ ValueAnimator animator = getFlingAnimator(prevDividerPosition, mDividerPosition);
+ animator.start();
+ } else {
+ onDraggingEnd();
+ }
+ }
+
+ @GuardedBy("mLock")
+ @NonNull
+ @VisibleForTesting
+ ValueAnimator getFlingAnimator(int prevDividerPosition, int snappedDividerPosition) {
+ final ValueAnimator animator =
+ getValueAnimator(prevDividerPosition, snappedDividerPosition);
+ animator.addUpdateListener(animation -> {
+ synchronized (mLock) {
+ updateDividerPosition((int) animation.getAnimatedValue());
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ synchronized (mLock) {
+ onDraggingEnd();
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ synchronized (mLock) {
+ onDraggingEnd();
+ }
+ }
+ });
+ return animator;
+ }
+
+ @VisibleForTesting
+ static ValueAnimator getValueAnimator(int prevDividerPosition, int snappedDividerPosition) {
+ ValueAnimator animator = ValueAnimator
+ .ofInt(prevDividerPosition, snappedDividerPosition)
+ .setDuration(FLING_ANIMATION_DURATION);
+ animator.setInterpolator(FLING_ANIMATION_INTERPOLATOR);
+ return animator;
+ }
+
+ @GuardedBy("mLock")
+ private void updateDividerPosition(int position) {
+ mRenderer.setDividerPosition(position);
mRenderer.updateSurface();
+ }
+ @GuardedBy("mLock")
+ private void onDraggingEnd() {
// Veil visibility change should be applied together with the surface boost transaction in
// the wct.
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
@@ -570,36 +661,76 @@ class DividerPresenter implements View.OnTouchListener {
/**
* Returns the divider position adjusted for the min max ratio and fullscreen expansion.
- *
- * If the dragging position is above the {@link DividerAttributes#getPrimaryMaxRatio()} or below
- * {@link DividerAttributes#getPrimaryMinRatio()} and
- * {@link DividerAttributes#isDraggingToFullscreenAllowed} is {@code true}, the system will
- * choose a snap algorithm to adjust the ending position to either fully expand one container or
- * move the divider back to the specified min/max ratio.
- *
- * TODO(b/327067596) implement snap algorithm
- *
* The adjusted divider position is in the range of [minPosition, maxPosition] for a split, 0
* for expanded right (bottom) container, or task width (height) minus the divider width for
* expanded left (top) container.
*/
@GuardedBy("mLock")
- private int adjustDividerPositionForSnapPoints(int dividerPosition) {
+ private int dividerPositionForSnapPoints(int dividerPosition, float velocity) {
final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
final int minPosition = calculateMinPosition();
final int maxPosition = calculateMaxPosition();
final int fullyExpandedPosition = mProperties.mIsVerticalSplit
? taskBounds.right - mRenderer.mDividerWidthPx
: taskBounds.bottom - mRenderer.mDividerWidthPx;
+
if (isDraggingToFullscreenAllowed(mProperties.mDividerAttributes)) {
- if (dividerPosition < minPosition) {
- return 0;
+ final float displayDensity = getDisplayDensity();
+ return dividerPositionWithDraggingToFullscreenAllowed(
+ dividerPosition,
+ minPosition,
+ maxPosition,
+ fullyExpandedPosition,
+ velocity,
+ displayDensity);
+ }
+ return Math.clamp(dividerPosition, minPosition, maxPosition);
+ }
+
+ /**
+ * Returns the divider position given a set of position options. A snap algorithm is used to
+ * adjust the ending position to either fully expand one container or move the divider back to
+ * the specified min/max ratio depending on the dragging velocity.
+ */
+ @VisibleForTesting
+ static int dividerPositionWithDraggingToFullscreenAllowed(int dividerPosition, int minPosition,
+ int maxPosition, int fullyExpandedPosition, float velocity, float displayDensity) {
+ final float minDismissVelocityPxPerSecond =
+ MIN_DISMISS_VELOCITY_DP_PER_SECOND * displayDensity;
+ final float minFlingVelocityPxPerSecond =
+ MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity;
+ if (dividerPosition < minPosition && velocity < -minDismissVelocityPxPerSecond) {
+ return 0;
+ }
+ if (dividerPosition > maxPosition && velocity > minDismissVelocityPxPerSecond) {
+ return fullyExpandedPosition;
+ }
+ if (Math.abs(velocity) < minFlingVelocityPxPerSecond) {
+ if (dividerPosition >= minPosition && dividerPosition <= maxPosition) {
+ return dividerPosition;
}
- if (dividerPosition > maxPosition) {
- return fullyExpandedPosition;
+ int[] possiblePositions = {0, minPosition, maxPosition, fullyExpandedPosition};
+ return snap(dividerPosition, possiblePositions);
+ }
+ if (velocity < 0) {
+ return 0;
+ } else {
+ return fullyExpandedPosition;
+ }
+ }
+
+ /** Calculates the snapped divider position based on the possible positions and distance. */
+ private static int snap(int dividerPosition, int[] possiblePositions) {
+ int snappedPosition = dividerPosition;
+ float minDistance = Float.MAX_VALUE;
+ for (int position : possiblePositions) {
+ float distance = Math.abs(dividerPosition - position);
+ if (distance < minDistance) {
+ snappedPosition = position;
+ minDistance = distance;
}
}
- return Math.clamp(dividerPosition, minPosition, maxPosition);
+ return snappedPosition;
}
private static void setDecorSurfaceBoosted(
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
index b0a45e285896..746607c8094c 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
@@ -19,6 +19,10 @@ package androidx.window.extensions.embedding;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE;
import static android.window.TaskFragmentOperation.OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE;
+import static androidx.window.extensions.embedding.DividerPresenter.FLING_ANIMATION_DURATION;
+import static androidx.window.extensions.embedding.DividerPresenter.FLING_ANIMATION_INTERPOLATOR;
+import static androidx.window.extensions.embedding.DividerPresenter.MIN_DISMISS_VELOCITY_DP_PER_SECOND;
+import static androidx.window.extensions.embedding.DividerPresenter.MIN_FLING_VELOCITY_DP_PER_SECOND;
import static androidx.window.extensions.embedding.DividerPresenter.getBoundsOffsetForDivider;
import static androidx.window.extensions.embedding.DividerPresenter.getInitialDividerPosition;
import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_BOTTOM;
@@ -35,6 +39,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Color;
@@ -637,6 +642,105 @@ public class DividerPresenterTest {
DividerPresenter.getContainerBackgroundColor(container, defaultColor));
}
+ @Test
+ public void testGetValueAnimator() {
+ ValueAnimator animator =
+ DividerPresenter.getValueAnimator(
+ 375 /* prevDividerPosition */,
+ 500 /* snappedDividerPosition */);
+
+ assertEquals(animator.getDuration(), FLING_ANIMATION_DURATION);
+ assertEquals(animator.getInterpolator(), FLING_ANIMATION_INTERPOLATOR);
+ }
+
+ @Test
+ public void testDividerPositionWithDraggingToFullscreenAllowed() {
+ final float displayDensity = 600F;
+ final float dismissVelocity = MIN_DISMISS_VELOCITY_DP_PER_SECOND * displayDensity + 10f;
+ final float nonFlingVelocity = MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity - 10f;
+ final float flingVelocity = MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity + 10f;
+
+ // Divider position is less than minPosition and the velocity is enough to be dismissed
+ assertEquals(
+ 0, // Closed position
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 10 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ -dismissVelocity,
+ displayDensity));
+
+ // Divider position is greater than maxPosition and the velocity is enough to be dismissed
+ assertEquals(
+ 1200, // Fully expanded position
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 1000 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ dismissVelocity,
+ displayDensity));
+
+ // Divider position is returned when the velocity is not fast enough for fling and is in
+ // between minPosition and maxPosition
+ assertEquals(
+ 500, // dividerPosition is not snapped
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 500 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ nonFlingVelocity,
+ displayDensity));
+
+ // Divider position is snapped when the velocity is not fast enough for fling and larger
+ // than maxPosition
+ assertEquals(
+ 900, // Closest position is maxPosition
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 950 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ nonFlingVelocity,
+ displayDensity));
+
+ // Divider position is snapped when the velocity is not fast enough for fling and smaller
+ // than minPosition
+ assertEquals(
+ 30, // Closest position is minPosition
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 20 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ nonFlingVelocity,
+ displayDensity));
+
+ // Divider position is greater than minPosition and the velocity is enough for fling
+ assertEquals(
+ 0, // Closed position
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 50 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ -flingVelocity,
+ displayDensity));
+
+ // Divider position is less than maxPosition and the velocity is enough for fling
+ assertEquals(
+ 1200, // Fully expanded position
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 800 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ flingVelocity,
+ displayDensity));
+ }
+
private TaskFragmentContainer createMockTaskFragmentContainer(
@NonNull IBinder token, @NonNull Rect bounds) {
final TaskFragmentContainer container = mock(TaskFragmentContainer.class);
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
index dcd4062cb819..785e30d879d2 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
@@ -69,8 +69,12 @@ public class TransitionUtil {
/** Returns {@code true} if the transition is opening or closing mode. */
public static boolean isOpenOrCloseMode(@TransitionInfo.TransitionMode int mode) {
- return mode == TRANSIT_OPEN || mode == TRANSIT_CLOSE
- || mode == TRANSIT_TO_FRONT || mode == TRANSIT_TO_BACK;
+ return isOpeningMode(mode) || mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK;
+ }
+
+ /** Returns {@code true} if the transition is opening mode. */
+ public static boolean isOpeningMode(@TransitionInfo.TransitionMode int mode) {
+ return mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT;
}
/** Returns {@code true} if the transition has a display change. */
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 9e6c5fbf9f5e..38c344322a30 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
@@ -87,6 +87,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
import com.android.launcher3.icons.BubbleIconFactory;
+import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
@@ -1170,7 +1171,9 @@ public class BubbleController implements ConfigurationChangeListener,
* @param bubbleKey key of the bubble being dragged
*/
public void startBubbleDrag(String bubbleKey) {
- onBubbleDrag(bubbleKey, true /* isBeingDragged */);
+ if (mBubbleData.getSelectedBubble() != null) {
+ mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ false);
+ }
if (mBubbleStateListener != null) {
boolean overflow = BubbleOverflow.KEY.equals(bubbleKey);
Rect rect = new Rect();
@@ -1183,23 +1186,29 @@ public class BubbleController implements ConfigurationChangeListener,
}
/**
- * A bubble is no longer being dragged in Launcher. As was released in given location.
+ * A bubble is no longer being dragged in Launcher. And was released in given location.
* Will be called only when bubble bar is expanded.
*
- * @param bubbleKey key of the bubble being dragged
* @param location location where bubble was released
*/
- public void stopBubbleDrag(String bubbleKey, BubbleBarLocation location) {
+ public void stopBubbleDrag(BubbleBarLocation location) {
mBubblePositioner.setBubbleBarLocation(location);
- onBubbleDrag(bubbleKey, false /* isBeingDragged */);
+ if (mBubbleData.getSelectedBubble() != null) {
+ mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ true);
+ }
}
- private void onBubbleDrag(String bubbleKey, boolean isBeingDragged) {
- // TODO(b/330585402): collapse stack if any bubble is dragged
- if (mBubbleData.getSelectedBubble() != null
- && mBubbleData.getSelectedBubble().getKey().equals(bubbleKey)) {
- // Should collapse/expand only if equals to selected bubble.
- mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ !isBeingDragged);
+ /**
+ * A bubble was dragged and is released in dismiss target in Launcher.
+ *
+ * @param bubbleKey key of the bubble being dragged to dismiss target
+ */
+ public void dragBubbleToDismiss(String bubbleKey) {
+ String selectedBubbleKey = mBubbleData.getSelectedBubbleKey();
+ removeBubble(bubbleKey, Bubbles.DISMISS_USER_GESTURE);
+ if (selectedBubbleKey != null && !selectedBubbleKey.equals(bubbleKey)) {
+ // We did not remove the selected bubble. Expand it again
+ mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ true);
}
}
@@ -1858,7 +1867,11 @@ public class BubbleController implements ConfigurationChangeListener,
@Override
public void bubbleOverflowChanged(boolean hasBubbles) {
- // TODO (b/334175587): tell stack view to hide / show the overflow
+ if (Flags.enableOptionalBubbleOverflow()) {
+ if (mStackView != null) {
+ mStackView.showOverflow(hasBubbles);
+ }
+ }
}
};
@@ -2358,12 +2371,6 @@ public class BubbleController implements ConfigurationChangeListener,
}
@Override
- public void removeBubble(String key) {
- mMainExecutor.execute(
- () -> mController.removeBubble(key, Bubbles.DISMISS_USER_GESTURE));
- }
-
- @Override
public void removeAllBubbles() {
mMainExecutor.execute(() -> mController.removeAllBubbles(Bubbles.DISMISS_USER_GESTURE));
}
@@ -2379,8 +2386,13 @@ public class BubbleController implements ConfigurationChangeListener,
}
@Override
- public void stopBubbleDrag(String bubbleKey, BubbleBarLocation location) {
- mMainExecutor.execute(() -> mController.stopBubbleDrag(bubbleKey, location));
+ public void stopBubbleDrag(BubbleBarLocation location) {
+ mMainExecutor.execute(() -> mController.stopBubbleDrag(location));
+ }
+
+ @Override
+ public void dragBubbleToDismiss(String key) {
+ mMainExecutor.execute(() -> mController.dragBubbleToDismiss(key));
}
@Override
@@ -2397,7 +2409,10 @@ public class BubbleController implements ConfigurationChangeListener,
@Override
public void setBubbleBarBounds(Rect bubbleBarBounds) {
- mMainExecutor.execute(() -> mBubblePositioner.setBubbleBarBounds(bubbleBarBounds));
+ mMainExecutor.execute(() -> {
+ mBubblePositioner.setBubbleBarBounds(bubbleBarBounds);
+ if (mLayerView != null) mLayerView.updateExpandedView();
+ });
}
}
@@ -2709,6 +2724,15 @@ public class BubbleController implements ConfigurationChangeListener,
() -> BubbleController.this.onSensitiveNotificationProtectionStateChanged(
sensitiveNotificationProtectionActive));
}
+
+ @Override
+ public boolean canShowBubbleNotification() {
+ // in bubble bar mode, when the IME is visible we can't animate new bubbles.
+ if (BubbleController.this.isShowingAsBubbleBar()) {
+ return !BubbleController.this.mBubblePositioner.getIsImeVisible();
+ }
+ return true;
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index ea30af5c3d5a..26483c8428c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -327,6 +327,14 @@ public class BubbleData {
return mSelectedBubble;
}
+ /**
+ * Returns the key of the selected bubble, or null if no bubble is selected.
+ */
+ @Nullable
+ public String getSelectedBubbleKey() {
+ return mSelectedBubble != null ? mSelectedBubble.getKey() : null;
+ }
+
public BubbleOverflow getOverflow() {
return mOverflow;
}
@@ -1228,9 +1236,7 @@ public class BubbleData {
public void dump(PrintWriter pw) {
pw.println("BubbleData state:");
pw.print(" selected: ");
- pw.println(mSelectedBubble != null
- ? mSelectedBubble.getKey()
- : "null");
+ pw.println(getSelectedBubbleKey());
pw.print(" expanded: ");
pw.println(mExpanded);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index 633b01bde4ca..18e04d14c71b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -44,6 +44,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ContrastColorUtil;
+import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
import java.util.ArrayList;
@@ -195,7 +196,9 @@ public class BubbleOverflowContainerView extends LinearLayout {
}
void updateEmptyStateVisibility() {
- mEmptyState.setVisibility(mOverflowBubbles.isEmpty() ? View.VISIBLE : View.GONE);
+ boolean showEmptyState = mOverflowBubbles.isEmpty()
+ && !Flags.enableOptionalBubbleOverflow();
+ mEmptyState.setVisibility(showEmptyState ? View.VISIBLE : View.GONE);
mRecyclerView.setVisibility(mOverflowBubbles.isEmpty() ? View.GONE : View.VISIBLE);
}
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 c4bbe32e3205..a35a004cdace 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
@@ -324,6 +324,11 @@ public class BubblePositioner {
return 0;
}
+ /** Returns whether the IME is visible. */
+ public boolean getIsImeVisible() {
+ return mImeVisible;
+ }
+
/** Sets whether the IME is visible. **/
public void setImeVisible(boolean visible, int height) {
mImeVisible = visible;
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 be88b3497000..9fabd4247670 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
@@ -80,6 +80,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.bubbles.BubblesNavBarMotionEventHandler.MotionEventListener;
@@ -863,6 +864,7 @@ public class BubbleStackView extends FrameLayout
}
};
+ private boolean mShowingOverflow;
private BubbleOverflow mBubbleOverflow;
private StackEducationView mStackEduView;
private StackEducationView.Manager mStackEducationViewManager;
@@ -992,18 +994,12 @@ public class BubbleStackView extends FrameLayout
mBubbleOverflow = mBubbleData.getOverflow();
- resetOverflowView();
- mBubbleContainer.addView(mBubbleOverflow.getIconView(),
- mBubbleContainer.getChildCount() /* index */,
- new FrameLayout.LayoutParams(mPositioner.getBubbleSize(),
- mPositioner.getBubbleSize()));
- updateOverflow();
- mBubbleOverflow.getIconView().setOnClickListener((View v) -> {
- mBubbleData.setShowingOverflow(true);
- mBubbleData.setSelectedBubble(mBubbleOverflow);
- mBubbleData.setExpanded(true);
- });
-
+ if (Flags.enableOptionalBubbleOverflow()) {
+ showOverflow(mBubbleData.hasOverflowBubbles());
+ } else {
+ mShowingOverflow = true; // if the flags not on this is always true
+ setUpOverflow();
+ }
mScrim = new View(getContext());
mScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
mScrim.setBackgroundDrawable(new ColorDrawable(
@@ -1220,6 +1216,19 @@ public class BubbleStackView extends FrameLayout
}
};
+ private void setUpOverflow() {
+ resetOverflowView();
+ mBubbleContainer.addView(mBubbleOverflow.getIconView(),
+ mBubbleContainer.getChildCount() /* index */,
+ new FrameLayout.LayoutParams(mBubbleSize, mBubbleSize));
+ updateOverflow();
+ mBubbleOverflow.getIconView().setOnClickListener((View v) -> {
+ mBubbleData.setShowingOverflow(true);
+ mBubbleData.setSelectedBubble(mBubbleOverflow);
+ mBubbleData.setExpanded(true);
+ });
+ }
+
private void setUpDismissView() {
if (mDismissView != null) {
removeView(mDismissView);
@@ -1458,24 +1467,56 @@ public class BubbleStackView extends FrameLayout
b.getExpandedView().updateFontSize();
}
}
- if (mBubbleOverflow != null && mBubbleOverflow.getExpandedView() != null) {
+ if (mShowingOverflow && mBubbleOverflow != null
+ && mBubbleOverflow.getExpandedView() != null) {
mBubbleOverflow.getExpandedView().updateFontSize();
}
}
void updateLocale() {
- if (mBubbleOverflow != null && mBubbleOverflow.getExpandedView() != null) {
+ if (mShowingOverflow && mBubbleOverflow != null
+ && mBubbleOverflow.getExpandedView() != null) {
mBubbleOverflow.getExpandedView().updateLocale();
}
}
private void updateOverflow() {
mBubbleOverflow.update();
- mBubbleContainer.reorderView(mBubbleOverflow.getIconView(),
- mBubbleContainer.getChildCount() - 1 /* index */);
+ if (mShowingOverflow) {
+ mBubbleContainer.reorderView(mBubbleOverflow.getIconView(),
+ mBubbleContainer.getChildCount() - 1 /* index */);
+ }
updateOverflowVisibility();
}
+ private void updateOverflowVisibility() {
+ mBubbleOverflow.setVisible(mShowingOverflow
+ && (mIsExpanded || mBubbleData.isShowingOverflow())
+ ? VISIBLE
+ : GONE);
+ }
+
+ private void updateOverflowDotVisibility(boolean expanding) {
+ if (mShowingOverflow && mBubbleOverflow.showDot()) {
+ mBubbleOverflow.getIconView().animateDotScale(expanding ? 1 : 0f, () -> {
+ mBubbleOverflow.setVisible(expanding ? VISIBLE : GONE);
+ });
+ }
+ }
+
+ /** Sets whether the overflow should be visible or not. */
+ public void showOverflow(boolean showOverflow) {
+ if (!Flags.enableOptionalBubbleOverflow()) return;
+ if (mShowingOverflow != showOverflow) {
+ mShowingOverflow = showOverflow;
+ if (showOverflow) {
+ setUpOverflow();
+ } else if (mBubbleOverflow != null) {
+ resetOverflowView();
+ }
+ }
+ }
+
/**
* Handle theme changes.
*/
@@ -1535,7 +1576,10 @@ public class BubbleStackView extends FrameLayout
b.getExpandedView().updateDimensions();
}
}
- mBubbleOverflow.getIconView().setLayoutParams(new LayoutParams(mBubbleSize, mBubbleSize));
+ if (mShowingOverflow) {
+ mBubbleOverflow.getIconView().setLayoutParams(
+ new LayoutParams(mBubbleSize, mBubbleSize));
+ }
mExpandedAnimationController.updateResources();
mStackAnimationController.updateResources();
mDismissView.updateResources();
@@ -1699,7 +1743,7 @@ public class BubbleStackView extends FrameLayout
bubble.getIconView().setContentDescription(getResources().getString(
R.string.bubble_content_description_single, titleStr, appName));
} else {
- final int moreCount = mBubbleContainer.getChildCount() - 1;
+ final int moreCount = getBubbleCount();
bubble.getIconView().setContentDescription(getResources().getString(
R.string.bubble_content_description_stack,
titleStr, appName, moreCount));
@@ -1752,7 +1796,8 @@ public class BubbleStackView extends FrameLayout
View bubbleOverflowIconView =
mBubbleOverflow != null ? mBubbleOverflow.getIconView() : null;
- if (bubbleOverflowIconView != null && !mBubbleData.getBubbles().isEmpty()) {
+ if (mShowingOverflow && bubbleOverflowIconView != null
+ && !mBubbleData.getBubbles().isEmpty()) {
Bubble lastBubble =
mBubbleData.getBubbles().get(mBubbleData.getBubbles().size() - 1);
View lastBubbleIconView = lastBubble.getIconView();
@@ -1928,20 +1973,6 @@ public class BubbleStackView extends FrameLayout
}
}
- private void updateOverflowVisibility() {
- mBubbleOverflow.setVisible((mIsExpanded || mBubbleData.isShowingOverflow())
- ? VISIBLE
- : GONE);
- }
-
- private void updateOverflowDotVisibility(boolean expanding) {
- if (mBubbleOverflow.showDot()) {
- mBubbleOverflow.getIconView().animateDotScale(expanding ? 1 : 0f, () -> {
- mBubbleOverflow.setVisible(expanding ? VISIBLE : GONE);
- });
- }
- }
-
// via BubbleData.Listener
void updateBubble(Bubble bubble) {
animateInFlyoutForBubble(bubble);
@@ -3428,8 +3459,9 @@ public class BubbleStackView extends FrameLayout
* @return the number of bubbles in the stack view.
*/
public int getBubbleCount() {
- // Subtract 1 for the overflow button that is always in the bubble container.
- return mBubbleContainer.getChildCount() - 1;
+ final int childCount = mBubbleContainer.getChildCount();
+ // Subtract 1 for the overflow button if it's showing.
+ return mShowingOverflow ? childCount - 1 : childCount;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 322088b17e63..1d053f9aab35 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -297,6 +297,15 @@ public interface Bubbles {
boolean sensitiveNotificationProtectionActive);
/**
+ * Determines whether Bubbles can show notifications.
+ *
+ * <p>Normally bubble notifications are shown by Bubbles, but in some cases the bubble
+ * notification is suppressed and should be shown by the Notifications pipeline as regular
+ * notifications.
+ */
+ boolean canShowBubbleNotification();
+
+ /**
* A listener to be notified of bubble state changes, used by launcher to render bubbles in
* its process.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
index 66f77fa6f76d..1eff149f2e91 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
@@ -33,7 +33,7 @@ interface IBubbles {
oneway void showBubble(in String key, in Rect bubbleBarBounds) = 3;
- oneway void removeBubble(in String key) = 4;
+ oneway void dragBubbleToDismiss(in String key) = 4;
oneway void removeAllBubbles() = 5;
@@ -47,5 +47,5 @@ interface IBubbles {
oneway void setBubbleBarBounds(in Rect bubbleBarBounds) = 10;
- oneway void stopBubbleDrag(in String key, in BubbleBarLocation location) = 11;
+ oneway void stopBubbleDrag(in BubbleBarLocation location) = 11;
} \ No newline at end of file
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 a351cef223b5..123cc7e9d488 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
@@ -356,7 +356,7 @@ public class BubbleBarLayerView extends FrameLayout
}
/** Updates the expanded view size and position. */
- private void updateExpandedView() {
+ public void updateExpandedView() {
if (mExpandedView == null || mExpandedBubble == null) return;
boolean isOverflowExpanded = mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
mPositioner.getBubbleBarExpandedViewBounds(mPositioner.isBubbleBarOnLeft(),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 607a3b5423d1..2234041b8c9d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -347,7 +347,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
if (mMoving) {
final int position = mSplitLayout.getDividerPosition() + touchPos - mStartPos;
mLastDraggingPosition = position;
- mSplitLayout.updateDividerBounds(position);
+ mSplitLayout.updateDividerBounds(position, true /* shouldUseParallaxEffect */);
}
break;
case MotionEvent.ACTION_UP:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index 30eb8b5d2f05..de016d3ae400 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -31,7 +31,6 @@ import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -57,7 +56,13 @@ import com.android.wm.shell.common.SurfaceUtils;
import java.util.function.Consumer;
/**
- * Handles split decor like showing resizing hint for a specific split.
+ * Handles additional layers over a running task in a split pair, for example showing a veil with an
+ * app icon when the task is being resized (usually to hide weird layouts while the app is being
+ * stretched). One SplitDecorManager is initialized on each window.
+ * <br>
+ * Currently, we show a veil when:
+ * a) Task is resizing down from a fullscreen window.
+ * b) Task is being stretched past its original bounds.
*/
public class SplitDecorManager extends WindowlessWindowManager {
private static final String TAG = SplitDecorManager.class.getSimpleName();
@@ -78,7 +83,11 @@ public class SplitDecorManager extends WindowlessWindowManager {
private boolean mShown;
private boolean mIsResizing;
- private final Rect mOldBounds = new Rect();
+ /** The original bounds of the main task, captured at the beginning of a resize transition. */
+ private final Rect mOldMainBounds = new Rect();
+ /** The original bounds of the side task, captured at the beginning of a resize transition. */
+ private final Rect mOldSideBounds = new Rect();
+ /** The current bounds of the main task, mid-resize. */
private final Rect mResizingBounds = new Rect();
private final Rect mTempRect = new Rect();
private ValueAnimator mFadeAnimator;
@@ -184,29 +193,38 @@ public class SplitDecorManager extends WindowlessWindowManager {
mResizingIconView = null;
mIsResizing = false;
mShown = false;
- mOldBounds.setEmpty();
+ mOldMainBounds.setEmpty();
+ mOldSideBounds.setEmpty();
mResizingBounds.setEmpty();
}
/** Showing resizing hint. */
public void onResizing(ActivityManager.RunningTaskInfo resizingTask, Rect newBounds,
Rect sideBounds, SurfaceControl.Transaction t, int offsetX, int offsetY,
- boolean immediately) {
+ boolean immediately, float[] veilColor) {
if (mResizingIconView == null) {
return;
}
if (!mIsResizing) {
mIsResizing = true;
- mOldBounds.set(newBounds);
+ mOldMainBounds.set(newBounds);
+ mOldSideBounds.set(sideBounds);
}
mResizingBounds.set(newBounds);
mOffsetX = offsetX;
mOffsetY = offsetY;
- final boolean show =
- newBounds.width() > mOldBounds.width() || newBounds.height() > mOldBounds.height();
- final boolean update = show != mShown;
+ // Show a veil when:
+ // a) Task is resizing down from a fullscreen window.
+ // b) Task is being stretched past its original bounds.
+ final boolean isResizingDownFromFullscreen =
+ mOldSideBounds.width() <= 1 || mOldSideBounds.height() <= 1;
+ final boolean isStretchingPastOriginalBounds =
+ newBounds.width() > mOldMainBounds.width()
+ || newBounds.height() > mOldMainBounds.height();
+ final boolean showVeil = isResizingDownFromFullscreen || isStretchingPastOriginalBounds;
+ final boolean update = showVeil != mShown;
if (update && mFadeAnimator != null && mFadeAnimator.isRunning()) {
// If we need to animate and animator still running, cancel it before we ensure both
// background and icon surfaces are non null for next animation.
@@ -216,18 +234,18 @@ public class SplitDecorManager extends WindowlessWindowManager {
if (mBackgroundLeash == null) {
mBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
RESIZING_BACKGROUND_SURFACE_NAME, mSurfaceSession);
- t.setColor(mBackgroundLeash, getResizingBackgroundColor(resizingTask))
+ t.setColor(mBackgroundLeash, veilColor)
.setLayer(mBackgroundLeash, Integer.MAX_VALUE - 1);
}
if (mGapBackgroundLeash == null && !immediately) {
final boolean isLandscape = newBounds.height() == sideBounds.height();
- final int left = isLandscape ? mOldBounds.width() : 0;
- final int top = isLandscape ? 0 : mOldBounds.height();
+ final int left = isLandscape ? mOldMainBounds.width() : 0;
+ final int top = isLandscape ? 0 : mOldMainBounds.height();
mGapBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
GAP_BACKGROUND_SURFACE_NAME, mSurfaceSession);
// Fill up another side bounds area.
- t.setColor(mGapBackgroundLeash, getResizingBackgroundColor(resizingTask))
+ t.setColor(mGapBackgroundLeash, veilColor)
.setLayer(mGapBackgroundLeash, Integer.MAX_VALUE - 2)
.setPosition(mGapBackgroundLeash, left, top)
.setWindowCrop(mGapBackgroundLeash, sideBounds.width(), sideBounds.height());
@@ -251,12 +269,12 @@ public class SplitDecorManager extends WindowlessWindowManager {
if (update) {
if (immediately) {
- t.setVisibility(mBackgroundLeash, show);
- t.setVisibility(mIconLeash, show);
+ t.setVisibility(mBackgroundLeash, showVeil);
+ t.setVisibility(mIconLeash, showVeil);
} else {
- startFadeAnimation(show, false, null);
+ startFadeAnimation(showVeil, false, null);
}
- mShown = show;
+ mShown = showVeil;
}
}
@@ -309,7 +327,8 @@ public class SplitDecorManager extends WindowlessWindowManager {
mIsResizing = false;
mOffsetX = 0;
mOffsetY = 0;
- mOldBounds.setEmpty();
+ mOldMainBounds.setEmpty();
+ mOldSideBounds.setEmpty();
mResizingBounds.setEmpty();
if (mFadeAnimator != null && mFadeAnimator.isRunning()) {
if (!mShown) {
@@ -346,14 +365,14 @@ public class SplitDecorManager extends WindowlessWindowManager {
/** Screenshot host leash and attach on it if meet some conditions */
public void screenshotIfNeeded(SurfaceControl.Transaction t) {
- if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
+ if (!mShown && mIsResizing && !mOldMainBounds.equals(mResizingBounds)) {
if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
mScreenshotAnimator.cancel();
} else if (mScreenshot != null) {
t.remove(mScreenshot);
}
- mTempRect.set(mOldBounds);
+ mTempRect.set(mOldMainBounds);
mTempRect.offsetTo(0, 0);
mScreenshot = ScreenshotUtils.takeScreenshot(t, mHostLeash, mTempRect,
Integer.MAX_VALUE - 1);
@@ -364,7 +383,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
public void setScreenshotIfNeeded(SurfaceControl screenshot, SurfaceControl.Transaction t) {
if (screenshot == null || !screenshot.isValid()) return;
- if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
+ if (!mShown && mIsResizing && !mOldMainBounds.equals(mResizingBounds)) {
if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
mScreenshotAnimator.cancel();
} else if (mScreenshot != null) {
@@ -465,9 +484,4 @@ public class SplitDecorManager extends WindowlessWindowManager {
mIcon = null;
}
}
-
- private static float[] getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
- final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
- return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).getComponents();
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 2ea32f44a78b..8331654839c9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -496,10 +496,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
* Updates bounds with the passing position. Usually used to update recording bounds while
* performing animation or dragging divider bar to resize the splits.
*/
- void updateDividerBounds(int position) {
+ void updateDividerBounds(int position, boolean shouldUseParallaxEffect) {
updateBounds(position);
mSplitLayoutHandler.onLayoutSizeChanging(this, mSurfaceEffectPolicy.mParallaxOffset.x,
- mSurfaceEffectPolicy.mParallaxOffset.y);
+ mSurfaceEffectPolicy.mParallaxOffset.y, shouldUseParallaxEffect);
}
void setDividerPosition(int position, boolean applyLayoutChange) {
@@ -647,7 +647,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
.setDuration(duration);
mDividerFlingAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mDividerFlingAnimator.addUpdateListener(
- animation -> updateDividerBounds((int) animation.getAnimatedValue()));
+ animation -> updateDividerBounds(
+ (int) animation.getAnimatedValue(), false /* shouldUseParallaxEffect */)
+ );
mDividerFlingAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -897,7 +899,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
* @see #applySurfaceChanges(SurfaceControl.Transaction, SurfaceControl, SurfaceControl,
* SurfaceControl, SurfaceControl, boolean)
*/
- void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY);
+ void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY,
+ boolean shouldUseParallaxEffect);
/**
* Calls when finish resizing the split bounds.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
index f9259e79472e..e8226051b672 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
@@ -16,8 +16,6 @@
package com.android.wm.shell.common.split;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED;
-
import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -26,25 +24,18 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import android.app.ActivityManager;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.Rect;
-import android.os.UserHandle;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.util.ArrayUtils;
import com.android.wm.shell.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
-import java.util.Arrays;
-import java.util.List;
-
/** Helper utility class for split screen components to use. */
public class SplitScreenUtils {
/** Reverse the split position. */
@@ -137,4 +128,10 @@ public class SplitScreenUtils {
return isLandscape;
}
}
+
+ /** Returns the specified background color that matches a RunningTaskInfo. */
+ public static Color getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
+ final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
+ return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index 414a9d1151ac..01364d1de279 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -133,6 +133,7 @@ public abstract class Pip2Module {
PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
@NonNull PipTransitionState pipTransitionState,
+ @NonNull PipScheduler pipScheduler,
@NonNull SizeSpecSource sizeSpecSource,
PipMotionHelper pipMotionHelper,
FloatingContentCoordinator floatingContentCoordinator,
@@ -140,7 +141,7 @@ public abstract class Pip2Module {
@ShellMainThread ShellExecutor mainExecutor,
Optional<PipPerfHintController> pipPerfHintControllerOptional) {
return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm,
- pipBoundsState, pipTransitionState, sizeSpecSource, pipMotionHelper,
+ pipBoundsState, pipTransitionState, pipScheduler, sizeSpecSource, pipMotionHelper,
floatingContentCoordinator, pipUiEventLogger, mainExecutor,
pipPerfHintControllerOptional);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 59d696918448..4bb10dfdf8c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -22,11 +22,11 @@ import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS;
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenUtils.getResizingBackgroundColor;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
@@ -41,7 +41,6 @@ import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
@@ -278,7 +277,7 @@ public class DragLayout extends LinearLayout
final int activityType = taskInfo1.getActivityType();
if (activityType == ACTIVITY_TYPE_STANDARD) {
Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
- int bgColor1 = getResizingBackgroundColor(taskInfo1);
+ int bgColor1 = getResizingBackgroundColor(taskInfo1).toArgb();
mDropZoneView1.setAppInfo(bgColor1, icon1);
mDropZoneView2.setAppInfo(bgColor1, icon1);
updateDropZoneSizes(null, null); // passing null splits the views evenly
@@ -298,10 +297,10 @@ public class DragLayout extends LinearLayout
mSplitScreenController.getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
if (topOrLeftTask != null && bottomOrRightTask != null) {
Drawable topOrLeftIcon = mIconProvider.getIcon(topOrLeftTask.topActivityInfo);
- int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask);
+ int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask).toArgb();
Drawable bottomOrRightIcon = mIconProvider.getIcon(
bottomOrRightTask.topActivityInfo);
- int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask);
+ int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask).toArgb();
mDropZoneView1.setAppInfo(topOrLeftColor, topOrLeftIcon);
mDropZoneView2.setAppInfo(bottomOrRightColor, bottomOrRightIcon);
}
@@ -556,11 +555,6 @@ public class DragLayout extends LinearLayout
}
}
- private static int getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
- final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
- return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb();
- }
-
/**
* Dumps information about this drag layout.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index e885262658f4..e1657f99639d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -854,7 +854,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipUiEventLoggerLogger.log(uiEventEnum);
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
- "onTaskAppeared: %s, state=%s", mTaskInfo.topActivity, mPipTransitionState);
+ "onTaskAppeared: %s, state=%s, taskId=%s", mTaskInfo.topActivity,
+ mPipTransitionState, mTaskInfo.taskId);
if (mPipTransitionState.getInSwipePipToHomeTransition()) {
if (!mWaitForFixedRotation) {
onEndOfSwipePipToHomeTransition();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index a097a0ffa47d..be10151ca5aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -58,7 +58,8 @@ import java.util.function.Consumer;
* A helper to animate and manipulate the PiP.
*/
public class PipMotionHelper implements PipAppOpsListener.Callback,
- FloatingContentCoordinator.FloatingContent {
+ FloatingContentCoordinator.FloatingContent,
+ PipTransitionState.PipTransitionStateChangedListener {
private static final String TAG = "PipMotionHelper";
private static final String FLING_BOUNDS_CHANGE = "fling_bounds_change";
private static final boolean DEBUG = false;
@@ -181,7 +182,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
}
};
mPipTransitionState = pipTransitionState;
- mPipTransitionState.addPipTransitionStateChangedListener(this::onPipTransitionStateChanged);
+ mPipTransitionState.addPipTransitionStateChangedListener(this);
}
void init() {
@@ -687,7 +688,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
// setAnimatingToBounds(toBounds);
}
- private void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
+ @Override
+ public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
@PipTransitionState.TransitionState int newState,
@Nullable Bundle extra) {
switch (newState) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
index 04cf350ddd3e..b55a41d8808f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
@@ -24,6 +24,7 @@ import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.hardware.input.InputManager;
+import android.os.Bundle;
import android.os.Looper;
import android.view.BatchedInputEventReceiver;
import android.view.Choreographer;
@@ -32,6 +33,7 @@ import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.InputMonitor;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
import android.view.ViewConfiguration;
import androidx.annotation.VisibleForTesting;
@@ -51,16 +53,20 @@ import java.util.function.Consumer;
* Helper on top of PipTouchHandler that handles inputs OUTSIDE of the PIP window, which is used to
* trigger dynamic resize.
*/
-public class PipResizeGestureHandler {
+public class PipResizeGestureHandler implements
+ PipTransitionState.PipTransitionStateChangedListener {
private static final String TAG = "PipResizeGestureHandler";
private static final int PINCH_RESIZE_SNAP_DURATION = 250;
private static final float PINCH_RESIZE_AUTO_MAX_RATIO = 0.9f;
+ private static final String RESIZE_BOUNDS_CHANGE = "resize_bounds_change";
private final Context mContext;
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
private final PipBoundsState mPipBoundsState;
private final PipTouchState mPipTouchState;
+ private final PipScheduler mPipScheduler;
+ private final PipTransitionState mPipTransitionState;
private final PhonePipMenuController mPhonePipMenuController;
private final PipUiEventLogger mPipUiEventLogger;
private final PipPinchResizingAlgorithm mPinchResizingAlgorithm;
@@ -88,6 +94,7 @@ public class PipResizeGestureHandler {
private boolean mIsSysUiStateValid;
private boolean mThresholdCrossed;
private boolean mOngoingPinchToResize = false;
+ private boolean mWaitingForBoundsChangeTransition = false;
private float mAngle = 0;
int mFirstIndex = -1;
int mSecondIndex = -1;
@@ -104,11 +111,17 @@ public class PipResizeGestureHandler {
private int mCtrlType;
private int mOhmOffset;
- public PipResizeGestureHandler(Context context, PipBoundsAlgorithm pipBoundsAlgorithm,
- PipBoundsState pipBoundsState, PipTouchState pipTouchState,
+ public PipResizeGestureHandler(Context context,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
+ PipBoundsState pipBoundsState,
+ PipTouchState pipTouchState,
+ PipScheduler pipScheduler,
+ PipTransitionState pipTransitionState,
Runnable updateMovementBoundsRunnable,
- PipUiEventLogger pipUiEventLogger, PhonePipMenuController menuActivityController,
- ShellExecutor mainExecutor, @Nullable PipPerfHintController pipPerfHintController) {
+ PipUiEventLogger pipUiEventLogger,
+ PhonePipMenuController menuActivityController,
+ ShellExecutor mainExecutor,
+ @Nullable PipPerfHintController pipPerfHintController) {
mContext = context;
mDisplayId = context.getDisplayId();
mMainExecutor = mainExecutor;
@@ -116,6 +129,11 @@ public class PipResizeGestureHandler {
mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipBoundsState = pipBoundsState;
mPipTouchState = pipTouchState;
+ mPipScheduler = pipScheduler;
+
+ mPipTransitionState = pipTransitionState;
+ mPipTransitionState.addPipTransitionStateChangedListener(this);
+
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
mPhonePipMenuController = menuActivityController;
mPipUiEventLogger = pipUiEventLogger;
@@ -125,6 +143,7 @@ public class PipResizeGestureHandler {
mUserResizeBounds.set(rect);
// mMotionHelper.synchronizePinnedStackBounds();
mUpdateMovementBoundsRunnable.run();
+ mPipBoundsState.setBounds(rect);
resetState();
};
}
@@ -202,7 +221,7 @@ public class PipResizeGestureHandler {
@VisibleForTesting
void onInputEvent(InputEvent ev) {
if (!mEnablePinchResize) {
- // No need to handle anything if neither form of resizing is enabled.
+ // No need to handle anything if resizing isn't enabled.
return;
}
@@ -227,7 +246,7 @@ public class PipResizeGestureHandler {
}
}
- if (mEnablePinchResize && mOngoingPinchToResize) {
+ if (mOngoingPinchToResize) {
onPinchResize(mv);
}
}
@@ -249,13 +268,11 @@ public class PipResizeGestureHandler {
}
boolean willStartResizeGesture(MotionEvent ev) {
- if (isInValidSysUiState()) {
- if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
- if (mEnablePinchResize && ev.getPointerCount() == 2) {
- onPinchResize(ev);
- mOngoingPinchToResize = mAllowGesture;
- return mAllowGesture;
- }
+ if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
+ if (mEnablePinchResize && ev.getPointerCount() == 2) {
+ onPinchResize(ev);
+ mOngoingPinchToResize = mAllowGesture;
+ return mAllowGesture;
}
}
return false;
@@ -284,7 +301,6 @@ public class PipResizeGestureHandler {
mSecondIndex = -1;
mAllowGesture = false;
finishResize();
- cleanUpHighPerfSessionMaybe();
}
if (ev.getPointerCount() != 2) {
@@ -347,10 +363,7 @@ public class PipResizeGestureHandler {
mDownSecondPoint, mLastPoint, mLastSecondPoint, mMinSize, mMaxSize,
mDownBounds, mLastResizeBounds);
- /*
- mPipTaskOrganizer.scheduleUserResizePip(mDownBounds, mLastResizeBounds,
- mAngle, null);
- */
+ mPipScheduler.scheduleUserResizePip(mLastResizeBounds, mAngle);
mPipBoundsState.setHasUserResizedPip(true);
}
}
@@ -399,57 +412,43 @@ public class PipResizeGestureHandler {
}
private void finishResize() {
- if (!mLastResizeBounds.isEmpty()) {
- // Pinch-to-resize needs to re-calculate snap fraction and animate to the snapped
- // position correctly. Drag-resize does not need to move, so just finalize resize.
- if (mOngoingPinchToResize) {
- final Rect startBounds = new Rect(mLastResizeBounds);
- // If user resize is pretty close to max size, just auto resize to max.
- if (mLastResizeBounds.width() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.x
- || mLastResizeBounds.height() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.y) {
- resizeRectAboutCenter(mLastResizeBounds, mMaxSize.x, mMaxSize.y);
- }
+ if (mLastResizeBounds.isEmpty()) {
+ resetState();
+ }
+ if (!mOngoingPinchToResize) {
+ return;
+ }
+ final Rect startBounds = new Rect(mLastResizeBounds);
- // If user resize is smaller than min size, auto resize to min
- if (mLastResizeBounds.width() < mMinSize.x
- || mLastResizeBounds.height() < mMinSize.y) {
- resizeRectAboutCenter(mLastResizeBounds, mMinSize.x, mMinSize.y);
- }
+ // If user resize is pretty close to max size, just auto resize to max.
+ if (mLastResizeBounds.width() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.x
+ || mLastResizeBounds.height() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.y) {
+ resizeRectAboutCenter(mLastResizeBounds, mMaxSize.x, mMaxSize.y);
+ }
- // get the current movement bounds
- final Rect movementBounds = mPipBoundsAlgorithm
- .getMovementBounds(mLastResizeBounds);
-
- // snap mLastResizeBounds to the correct edge based on movement bounds
- snapToMovementBoundsEdge(mLastResizeBounds, movementBounds);
-
- final float snapFraction = mPipBoundsAlgorithm.getSnapFraction(
- mLastResizeBounds, movementBounds);
- mPipBoundsAlgorithm.applySnapFraction(mLastResizeBounds, snapFraction);
-
- // disable any touch events beyond resizing too
- mPipTouchState.setAllowInputEvents(false);
-
- /*
- mPipTaskOrganizer.scheduleAnimateResizePip(startBounds, mLastResizeBounds,
- PINCH_RESIZE_SNAP_DURATION, mAngle, mUpdateResizeBoundsCallback, () -> {
- // enable touch events
- mPipTouchState.setAllowInputEvents(true);
- });
- */
- } else {
- /*
- mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds,
- TRANSITION_DIRECTION_USER_RESIZE,
- mUpdateResizeBoundsCallback);
- */
- }
- final float magnetRadiusPercent = (float) mLastResizeBounds.width() / mMinSize.x / 2.f;
- mPipUiEventLogger.log(
- PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_RESIZE);
- } else {
- resetState();
+ // If user resize is smaller than min size, auto resize to min
+ if (mLastResizeBounds.width() < mMinSize.x
+ || mLastResizeBounds.height() < mMinSize.y) {
+ resizeRectAboutCenter(mLastResizeBounds, mMinSize.x, mMinSize.y);
}
+
+ // get the current movement bounds
+ final Rect movementBounds = mPipBoundsAlgorithm
+ .getMovementBounds(mLastResizeBounds);
+
+ // snap mLastResizeBounds to the correct edge based on movement bounds
+ snapToMovementBoundsEdge(mLastResizeBounds, movementBounds);
+
+ final float snapFraction = mPipBoundsAlgorithm.getSnapFraction(
+ mLastResizeBounds, movementBounds);
+ mPipBoundsAlgorithm.applySnapFraction(mLastResizeBounds, snapFraction);
+
+ // Update the transition state to schedule a resize transition.
+ Bundle extra = new Bundle();
+ extra.putBoolean(RESIZE_BOUNDS_CHANGE, true);
+ mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
+
+ mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_RESIZE);
}
private void resetState() {
@@ -509,6 +508,40 @@ public class PipResizeGestureHandler {
rect.set(l, t, r, b);
}
+ @Override
+ public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
+ @PipTransitionState.TransitionState int newState, @Nullable Bundle extra) {
+ switch (newState) {
+ case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
+ if (!extra.getBoolean(RESIZE_BOUNDS_CHANGE)) break;
+ mWaitingForBoundsChangeTransition = true;
+ mPipScheduler.scheduleAnimateResizePip(mLastResizeBounds);
+ break;
+ case PipTransitionState.CHANGING_PIP_BOUNDS:
+ if (!mWaitingForBoundsChangeTransition) break;
+
+ // If bounds change transition was scheduled from this class, handle leash updates.
+ mWaitingForBoundsChangeTransition = false;
+
+ SurfaceControl.Transaction startTx = extra.getParcelable(
+ PipTransition.PIP_START_TX, SurfaceControl.Transaction.class);
+ Rect destinationBounds = extra.getParcelable(
+ PipTransition.PIP_DESTINATION_BOUNDS, Rect.class);
+ startTx.setPosition(mPipTransitionState.mPinnedTaskLeash,
+ destinationBounds.left, destinationBounds.top);
+ startTx.apply();
+
+ // All motion operations have actually finished, so make bounds cache updates.
+ cleanUpHighPerfSessionMaybe();
+
+ // Setting state to CHANGED_PIP_BOUNDS applies finishTx and notifies Core.
+ mPipTransitionState.setState(PipTransitionState.CHANGED_PIP_BOUNDS);
+
+ mUpdateResizeBoundsCallback.accept(destinationBounds);
+ break;
+ }
+ }
+
/**
* Dumps the {@link PipResizeGestureHandler} state.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index c5b0de31f104..49475077211f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -24,6 +24,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.graphics.Matrix;
import android.graphics.Rect;
import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
@@ -165,6 +166,16 @@ public class PipScheduler {
* {@link WindowContainerTransaction}.
*/
public void scheduleUserResizePip(Rect toBounds) {
+ scheduleUserResizePip(toBounds, 0f /* degrees */);
+ }
+
+ /**
+ * Directly perform a scaled matrix transformation on the leash. This will not perform any
+ * {@link WindowContainerTransaction}.
+ *
+ * @param degrees the angle to rotate the bounds to.
+ */
+ public void scheduleUserResizePip(Rect toBounds, float degrees) {
if (toBounds.isEmpty()) {
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Attempted to user resize PIP to empty bounds, aborting.", TAG);
@@ -172,7 +183,16 @@ public class PipScheduler {
}
SurfaceControl leash = mPipTransitionState.mPinnedTaskLeash;
final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
- tx.setPosition(leash, toBounds.left, toBounds.top);
+
+ Matrix transformTensor = new Matrix();
+ final float[] mMatrixTmp = new float[9];
+ final float scale = (float) toBounds.width() / mPipBoundsState.getBounds().width();
+
+ transformTensor.setScale(scale, scale);
+ transformTensor.postTranslate(toBounds.left, toBounds.top);
+ transformTensor.postRotate(degrees, toBounds.centerX(), toBounds.centerY());
+
+ tx.setMatrix(leash, transformTensor, mMatrixTmp);
tx.apply();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index 9c6e3ea494fa..319d1999a272 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -73,7 +73,7 @@ import java.util.Optional;
* Manages all the touch handling for PIP on the Phone, including moving, dismissing and expanding
* the PIP.
*/
-public class PipTouchHandler {
+public class PipTouchHandler implements PipTransitionState.PipTransitionStateChangedListener {
private static final String TAG = "PipTouchHandler";
private static final float DEFAULT_STASH_VELOCITY_THRESHOLD = 18000.f;
@@ -84,6 +84,7 @@ public class PipTouchHandler {
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
@NonNull private final PipBoundsState mPipBoundsState;
@NonNull private final PipTransitionState mPipTransitionState;
+ @NonNull private final PipScheduler mPipScheduler;
@NonNull private final SizeSpecSource mSizeSpecSource;
private final PipUiEventLogger mPipUiEventLogger;
private final PipDismissTargetHandler mPipDismissTargetHandler;
@@ -173,6 +174,7 @@ public class PipTouchHandler {
PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
@NonNull PipTransitionState pipTransitionState,
+ @NonNull PipScheduler pipScheduler,
@NonNull SizeSpecSource sizeSpecSource,
PipMotionHelper pipMotionHelper,
FloatingContentCoordinator floatingContentCoordinator,
@@ -188,6 +190,7 @@ public class PipTouchHandler {
mPipTransitionState = pipTransitionState;
mPipTransitionState.addPipTransitionStateChangedListener(this::onPipTransitionStateChanged);
+ mPipScheduler = pipScheduler;
mSizeSpecSource = sizeSpecSource;
mMenuController = menuController;
mPipUiEventLogger = pipUiEventLogger;
@@ -213,10 +216,10 @@ public class PipTouchHandler {
},
menuController::hideMenu,
mainExecutor);
- mPipResizeGestureHandler =
- new PipResizeGestureHandler(context, pipBoundsAlgorithm, pipBoundsState,
- mTouchState, this::updateMovementBounds, pipUiEventLogger,
- menuController, mainExecutor, mPipPerfHintController);
+ mPipResizeGestureHandler = new PipResizeGestureHandler(context, pipBoundsAlgorithm,
+ pipBoundsState, mTouchState, mPipScheduler, mPipTransitionState,
+ this::updateMovementBounds, pipUiEventLogger, menuController, mainExecutor,
+ mPipPerfHintController);
mPipBoundsState.addOnAspectRatioChangedCallback(this::updateMinMaxSize);
if (PipUtils.isPip2ExperimentEnabled()) {
@@ -1075,7 +1078,8 @@ public class PipTouchHandler {
mPipResizeGestureHandler.setOhmOffset(offset);
}
- private void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
+ @Override
+ public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
@PipTransitionState.TransitionState int newState,
@Nullable Bundle extra) {
switch (newState) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index b10176df5826..4299088a51f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -43,10 +43,12 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.common.split.SplitScreenConstants.splitPositionToString;
+import static com.android.wm.shell.common.split.SplitScreenUtils.getResizingBackgroundColor;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
+import static com.android.wm.shell.shared.TransitionUtil.isOpeningMode;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
@@ -67,6 +69,7 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_UNKNOWN;
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
+import static com.android.wm.shell.transition.MixedTransitionHelper.getPipReplacingChange;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -2386,14 +2389,20 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
- public void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY) {
+ public void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY,
+ boolean shouldUseParallaxEffect) {
final SurfaceControl.Transaction t = mTransactionPool.acquire();
t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
- updateSurfaceBounds(layout, t, true /* applyResizingOffset */);
+ updateSurfaceBounds(layout, t, shouldUseParallaxEffect);
getMainStageBounds(mTempRect1);
getSideStageBounds(mTempRect2);
- mMainStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately);
- mSideStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately);
+ // TODO (b/307490004): "commonColor" below is a temporary fix to ensure the colors on both
+ // sides match. When b/307490004 is fixed, this code can be reverted.
+ float[] commonColor = getResizingBackgroundColor(mSideStage.mRootTaskInfo).getComponents();
+ mMainStage.onResizing(
+ mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately, commonColor);
+ mSideStage.onResizing(
+ mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately, commonColor);
t.apply();
mTransactionPool.release(t);
}
@@ -2836,7 +2845,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.setFreezeDividerWindow(false);
final StageChangeRecord record = new StageChangeRecord();
final int transitType = info.getType();
- boolean hasEnteringPip = false;
+ TransitionInfo.Change pipChange = null;
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
final TransitionInfo.Change change = info.getChanges().get(iC);
if (change.getMode() == TRANSIT_CHANGE
@@ -2847,7 +2856,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
if (mMixedHandler.isEnteringPip(change, transitType)) {
- hasEnteringPip = true;
+ pipChange = change;
}
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
@@ -2899,9 +2908,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
- if (hasEnteringPip) {
+ if (pipChange != null) {
+ TransitionInfo.Change pipReplacingChange = getPipReplacingChange(info, pipChange,
+ mMainStage.mRootTaskInfo.taskId, mSideStage.mRootTaskInfo.taskId,
+ getSplitItemStage(pipChange.getLastParent()));
+ if (pipReplacingChange != null) {
+ // Set an enter transition for when startAnimation gets called again
+ mSplitTransitions.setEnterTransition(transition, /*remoteTransition*/ null,
+ TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, /*resizeAnim*/ false);
+ }
+
mMixedHandler.animatePendingEnterPipFromSplit(transition, info,
- startTransaction, finishTransaction, finishCallback);
+ startTransaction, finishTransaction, finishCallback,
+ pipReplacingChange != null);
notifySplitAnimationFinished();
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 1e305c5dbbcf..0f3d6cade95a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -177,9 +177,11 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
@CallSuper
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskAppeared: task=%d taskParent=%d rootTask=%d",
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskAppeared: taskId=%d taskParent=%d rootTask=%d "
+ + "taskActivity=%s",
taskInfo.taskId, taskInfo.parentTaskId,
- mRootTaskInfo != null ? mRootTaskInfo.taskId : -1);
+ mRootTaskInfo != null ? mRootTaskInfo.taskId : -1,
+ taskInfo.baseActivity);
if (mRootTaskInfo == null) {
mRootLeash = leash;
mRootTaskInfo = taskInfo;
@@ -213,6 +215,8 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
@CallSuper
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: taskId=%d taskAct=%s",
+ taskInfo.taskId, taskInfo.baseActivity);
mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
if (mRootTaskInfo.taskId == taskInfo.taskId) {
// Inflates split decor view only when the root task is visible.
@@ -310,10 +314,10 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
void onResizing(Rect newBounds, Rect sideBounds, SurfaceControl.Transaction t, int offsetX,
- int offsetY, boolean immediately) {
+ int offsetY, boolean immediately, float[] veilColor) {
if (mSplitDecorManager != null && mRootTaskInfo != null) {
mSplitDecorManager.onResizing(mRootTaskInfo, newBounds, sideBounds, t, offsetX,
- offsetY, immediately);
+ offsetY, immediately, veilColor);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 968b27b62490..bcacecbd8981 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -77,6 +77,7 @@ public class DefaultMixedHandler implements MixedTransitionHandler,
private ActivityEmbeddingController mActivityEmbeddingController;
abstract static class MixedTransition {
+ /** Entering Pip from split, breaks split. */
static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
/** Both the display and split-state (enter/exit) is changing */
@@ -103,6 +104,9 @@ public class DefaultMixedHandler implements MixedTransitionHandler,
/** Enter pip from one of the Activity Embedding windows. */
static final int TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING = 9;
+ /** Entering Pip from split, but replace the Pip stage instead of breaking split. */
+ static final int TYPE_ENTER_PIP_REPLACE_FROM_SPLIT = 10;
+
/** The default animation for this mixed transition. */
static final int ANIM_TYPE_DEFAULT = 0;
@@ -484,9 +488,11 @@ public class DefaultMixedHandler implements MixedTransitionHandler,
// TODO(b/287704263): Remove when split/mixed are reversed.
public boolean animatePendingEnterPipFromSplit(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- Transitions.TransitionFinishCallback finishCallback) {
- final MixedTransition mixed = createDefaultMixedTransition(
- MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT, transition);
+ Transitions.TransitionFinishCallback finishCallback, boolean replacingPip) {
+ int type = replacingPip
+ ? MixedTransition.TYPE_ENTER_PIP_REPLACE_FROM_SPLIT
+ : MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT;
+ final MixedTransition mixed = createDefaultMixedTransition(type, transition);
mActiveTransitions.add(mixed);
Transitions.TransitionFinishCallback callback = wct -> {
mActiveTransitions.remove(mixed);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
index b028bd65b438..0ada74937df4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
@@ -76,7 +76,12 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition {
info, startTransaction, finishTransaction, finishCallback);
case TYPE_ENTER_PIP_FROM_SPLIT ->
animateEnterPipFromSplit(this, info, startTransaction, finishTransaction,
- finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler);
+ finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler,
+ /*replacingPip*/ false);
+ case TYPE_ENTER_PIP_REPLACE_FROM_SPLIT ->
+ animateEnterPipFromSplit(this, info, startTransaction, finishTransaction,
+ finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler,
+ /*replacingPip*/ true);
case TYPE_KEYGUARD ->
animateKeyguard(this, info, startTransaction, finishTransaction, finishCallback,
mKeyguardHandler, mPipHandler);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
index ffc0b76b131d..e8b01b5880fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
@@ -23,11 +23,15 @@ import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
+import static com.android.wm.shell.shared.TransitionUtil.isOpeningMode;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
import static com.android.wm.shell.transition.DefaultMixedHandler.subCopy;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
@@ -45,7 +49,8 @@ public class MixedTransitionHelper {
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull Transitions player, @NonNull MixedTransitionHandler mixedHandler,
- @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler) {
+ @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler,
+ boolean replacingPip) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animating a mixed transition for "
+ "entering PIP while Split-Screen is foreground.");
TransitionInfo.Change pipChange = null;
@@ -99,7 +104,7 @@ public class MixedTransitionHelper {
// we need a separate one to send over to launcher.
SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction();
@SplitScreen.StageType int topStageToKeep = STAGE_TYPE_UNDEFINED;
- if (splitHandler.isSplitScreenVisible()) {
+ if (splitHandler.isSplitScreenVisible() && !replacingPip) {
// The non-going home case, we could be pip-ing one of the split stages and keep
// showing the other
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
@@ -115,11 +120,12 @@ public class MixedTransitionHelper {
break;
}
}
+
+ // Let split update internal state for dismiss.
+ splitHandler.prepareDismissAnimation(topStageToKeep,
+ EXIT_REASON_CHILD_TASK_ENTER_PIP, everythingElse, otherStartT,
+ finishTransaction);
}
- // Let split update internal state for dismiss.
- splitHandler.prepareDismissAnimation(topStageToKeep,
- EXIT_REASON_CHILD_TASK_ENTER_PIP, everythingElse, otherStartT,
- finishTransaction);
// We are trying to accommodate launcher's close animation which can't handle the
// divider-bar, so if split-handler is closing the divider-bar, just hide it and
@@ -152,6 +158,44 @@ public class MixedTransitionHelper {
return true;
}
+ /**
+ * Check to see if we're only closing split to enter pip or if we're replacing pip with
+ * another task. If we are replacing, this will return the change for the task we are replacing
+ * pip with
+ *
+ * @param info Any number of changes
+ * @param pipChange TransitionInfo.Change indicating the task that is being pipped
+ * @param splitMainStageRootId MainStage's rootTaskInfo's id
+ * @param splitSideStageRootId SideStage's rootTaskInfo's id
+ * @param lastPipSplitStage The last stage that {@param pipChange} was in
+ * @return The change from {@param info} that is replacing the {@param pipChange}, {@code null}
+ * otherwise
+ */
+ @Nullable
+ public static TransitionInfo.Change getPipReplacingChange(TransitionInfo info,
+ TransitionInfo.Change pipChange, int splitMainStageRootId, int splitSideStageRootId,
+ @SplitScreen.StageType int lastPipSplitStage) {
+ int lastPipParentTask = -1;
+ if (lastPipSplitStage == STAGE_TYPE_MAIN) {
+ lastPipParentTask = splitMainStageRootId;
+ } else if (lastPipSplitStage == STAGE_TYPE_SIDE) {
+ lastPipParentTask = splitSideStageRootId;
+ }
+
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ TransitionInfo.Change change = info.getChanges().get(i);
+ if (change == pipChange || !isOpeningMode(change.getMode())) {
+ // Ignore the change/task that's going into Pip or not opening
+ continue;
+ }
+
+ if (change.getTaskInfo().parentTaskId == lastPipParentTask) {
+ return change;
+ }
+ }
+ return null;
+ }
+
private static boolean isHomeOpening(@NonNull TransitionInfo.Change change) {
return change.getTaskInfo() != null
&& change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
index d6e64cfaf4d5..9fc6702562bb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
@@ -142,7 +142,8 @@ class RecentsMixedTransition extends DefaultMixedHandler.MixedTransition {
&& mSplitHandler.getSplitItemPosition(change.getLastParent())
!= SPLIT_POSITION_UNDEFINED) {
return animateEnterPipFromSplit(this, info, startTransaction, finishTransaction,
- finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler);
+ finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler,
+ /*replacingPip*/ false);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 4d3c76322fa8..6224543516fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -31,7 +31,6 @@ import static android.view.WindowManager.fixScale;
import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
-import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
import static android.window.TransitionInfo.FLAG_NO_ANIMATION;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
@@ -567,15 +566,15 @@ public class Transitions implements RemoteCallable<Transitions>,
final int mode = change.getMode();
// Put all the OPEN/SHOW on top
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
- if (isOpening
- // This is for when an activity launches while a different transition is
- // collecting.
- || change.hasFlags(FLAG_MOVED_TO_TOP)) {
+ if (isOpening) {
// put on top
return zSplitLine + numChanges - i;
- } else {
+ } else if (isClosing) {
// put on bottom
return zSplitLine - i;
+ } else {
+ // maintain relative ordering (put all changes in the animating layer)
+ return zSplitLine + numChanges - i;
}
} else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
if (isOpening) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 8de60b7acc91..cfe8e07aa6e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -26,6 +26,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_STA
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
@@ -115,9 +116,9 @@ public class SplitLayoutTests extends ShellTestCase {
@Test
public void testUpdateDivideBounds() {
- mSplitLayout.updateDividerBounds(anyInt());
+ mSplitLayout.updateDividerBounds(anyInt(), anyBoolean());
verify(mSplitLayoutHandler).onLayoutSizeChanging(any(SplitLayout.class), anyInt(),
- anyInt());
+ anyInt(), anyBoolean());
}
@Test
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index b43ff63f3fcc..a4887567b075 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -252,18 +252,14 @@ public final class MediaController {
return 0;
}
- /**
- * Get the current playback info for this session.
- *
- * @return The current playback info or null.
- */
- public @Nullable PlaybackInfo getPlaybackInfo() {
+ /** Returns the current playback info for this session. */
+ @NonNull
+ public PlaybackInfo getPlaybackInfo() {
try {
return mSessionBinder.getVolumeAttributes();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getAudioInfo.", e);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
- return null;
}
/**
diff --git a/nfc/java/android/nfc/cardemulation/HostApduService.java b/nfc/java/android/nfc/cardemulation/HostApduService.java
index f674b06ad33d..c3c74a6fd265 100644
--- a/nfc/java/android/nfc/cardemulation/HostApduService.java
+++ b/nfc/java/android/nfc/cardemulation/HostApduService.java
@@ -20,6 +20,7 @@ import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -404,6 +405,7 @@ public abstract class HostApduService extends Service {
*
* @param frame A description of the polling frame.
*/
+ @SuppressLint("OnNameExpected")
@FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
public void processPollingFrames(@NonNull List<PollingFrame> frame) {
}
diff --git a/packages/SettingsLib/DataStore/README.md b/packages/SettingsLib/DataStore/README.md
index 30cb9932f104..a762ad3fe199 100644
--- a/packages/SettingsLib/DataStore/README.md
+++ b/packages/SettingsLib/DataStore/README.md
@@ -1,55 +1,93 @@
# Datastore library
-This library aims to manage datastore in a consistent way.
+This library provides consistent API for data management (including backup,
+restore, and metrics logging) on Android platform.
+
+Notably, it is designed to be flexible and could be utilized for a wide range of
+data store besides the settings preferences.
## Overview
-A datastore is required to extend the `BackupRestoreStorage` class and implement
-either `Observable` or `KeyedObservable` interface, which enforces:
-
-- Backup and restore: Datastore should support
- [data backup](https://developer.android.com/guide/topics/data/backup) to
- preserve user experiences on a new device.
-- Observer pattern: The
- [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) allows to
- monitor data change in the datastore and
- - trigger
- [BackupManager.dataChanged](https://developer.android.com/reference/android/app/backup/BackupManager#dataChanged\(\))
- automatically.
- - track data change event to log metrics.
- - update internal state and take action.
+In the high-level design, a persistent datastore aims to support two key
+characteristics:
+
+- **observable**: triggers backup and metrics logging whenever data is
+ changed.
+- **transferable**: offers users with a seamless experience by backing up and
+ restoring data on to new devices.
+
+More specifically, Android framework supports
+[data backup](https://developer.android.com/guide/topics/data/backup) to
+preserve user experiences on a new device. And the
+[observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) allows to
+monitor data change.
### Backup and restore
-The Android backup framework provides
+Currently, the Android backup framework provides
[BackupAgentHelper](https://developer.android.com/reference/android/app/backup/BackupAgentHelper)
and
[BackupHelper](https://developer.android.com/reference/android/app/backup/BackupHelper)
-to back up a datastore. However, there are several caveats when implement
-`BackupHelper`:
+to facilitate data backup. However, there are several caveats to consider when
+implementing `BackupHelper`:
-- performBackup: The data is updated incrementally but it is not well
+- *performBackup*: The data is updated incrementally but it is not well
documented. The `ParcelFileDescriptor` state parameters are normally ignored
and data is updated even there is no change.
-- restoreEntity: The implementation must take care not to seek or close the
- underlying data source, nor read more than size() bytes from the stream when
- restore (see
+- *restoreEntity*: The implementation must take care not to seek or close the
+ underlying data source, nor read more than `size()` bytes from the stream
+ when restore (see
[BackupDataInputStream](https://developer.android.com/reference/android/app/backup/BackupDataInputStream)).
- It is possible a `BackupHelper` prevents other `BackupHelper`s from
- restoring data.
-- writeNewStateDescription: Existing implementations rarely notice that this
- callback is invoked after all entities are restored, and check if necessary
- data are all restored in `restoreEntity` (e.g.
+ It is possible that a `BackupHelper` interferes with the restore process of
+ other `BackupHelper`s.
+- *writeNewStateDescription*: Existing implementations rarely notice that this
+ callback is invoked after *all* entities are restored. Instead, they check
+ if necessary data are all restored in the `restoreEntity` (e.g.
[BatteryBackupHelper](https://cs.android.com/android/platform/superproject/main/+/main:packages/apps/Settings/src/com/android/settings/fuelgauge/BatteryBackupHelper.java;l=144;drc=cca804e1ed504e2d477be1e3db00fb881ca32736)),
which is not robust sometimes.
-This library provides more clear API and offers some improvements:
+The datastore library will mitigate these problems by providing alternative
+APIs. For instance, library users make use of `InputStream` / `OutputStream` to
+back up and restore data directly.
+
+### Observer pattern
+
+In the current implementation, the Android backup framework requires a manual
+call to
+[BackupManager.dataChanged](https://developer.android.com/reference/android/app/backup/BackupManager#dataChanged\(\)).
+However, it's often observed that this API call is forgotten when using
+`SharedPreferences`. Additionally, there's a common need to log metrics when
+data changed. To address these limitations, datastore API employed the observer
+pattern.
+
+### API design and advantages
-- The implementation only needs to focus on the `BackupRestoreEntity`
- interface. The `InputStream` of restore will ensure bounded data are read,
- and close the stream will be no-op.
-- The library computes checksum of the backup data automatically, so that
- unchanged data will not be sent to Android backup system.
+Datastore must extend the `BackupRestoreStorage` class (subclass of
+[BackupHelper](https://developer.android.com/reference/android/app/backup/BackupHelper)).
+The data in a datastore is group by entity, which is represented by
+`BackupRestoreEntity`. Basically, a datastore implementation only needs to focus
+on the `BackupRestoreEntity`.
+
+If the datastore is key-value based (e.g. `SharedPreferences`), implements the
+`KeyedObservable` interface to offer fine-grained observer. Otherwise,
+implements `Observable`. There are builtin thread-safe implementations of the
+two interfaces (`KeyedDataObservable` / `DataObservable`). If it is Kotlin, use
+delegation to simplify the code.
+
+Keep in mind that the implementation should call `KeyedObservable.notifyChange`
+/ `Observable.notifyChange` whenever internal data is changed, so that the
+registered observer will be notified properly.
+
+For `SharedPreferences` use case, leverage the `SharedPreferencesStorage`
+directly. To back up other file based storage, extend the
+`BackupRestoreFileStorage` class.
+
+Here are some highlights of the library:
+
+- The restore `InputStream` will ensure bounded data are read, and close the
+ stream is no-op. That being said, all entities are isolated.
+- Data checksum is computed automatically, unchanged data will not be sent to
+ Android backup system.
- Data compression is supported:
- ZIP best compression is enabled by default, no extra effort needs to be
taken.
@@ -67,98 +105,159 @@ This library provides more clear API and offers some improvements:
successfully restored in those older versions. This is achieved by extending
the `BackupRestoreFileStorage` class, and `BackupRestoreFileArchiver` will
treat each file as an entity and do the backup / restore.
-- Manual `BackupManager.dataChanged` call is unnecessary now, the library will
- do the invocation (see next section).
+- Manual `BackupManager.dataChanged` call is unnecessary now, the framework
+ will invoke the API automatically.
-### Observer pattern
+## Usages
-Manual `BackupManager.dataChanged` call is required by current backup framework.
-In practice, it is found that `SharedPreferences` usages foget to invoke the
-API. Besides, there are common use cases to log metrics when data is changed.
-Consequently, observer pattern is employed to resolve the issues.
+This section provides [examples](example/ExampleStorage.kt) of datastore.
-If the datastore is key-value based (e.g. `SharedPreferences`), implements the
-`KeyedObservable` interface to offer fine-grained observer. Otherwise,
-implements `Observable`. The library provides thread-safe implementations
-(`KeyedDataObservable` / `DataObservable`), and Kotlin delegation will be
-helpful.
+Here is a datastore with a string data:
-Keep in mind that the implementation should call `KeyedObservable.notifyChange`
-/ `Observable.notifyChange` whenever internal data is changed, so that the
-registered observer will be notified properly.
+```kotlin
+class ExampleStorage : ObservableBackupRestoreStorage() {
+ @Volatile // field is manipulated by multiple threads, synchronization might be needed
+ var data: String? = null
+ private set
-## Usage and example
+ @AnyThread
+ fun setData(data: String?) {
+ this.data = data
+ // call notifyChange to trigger backup and metrics logging whenever data is changed
+ if (data != null) {
+ notifyChange(ChangeReason.UPDATE)
+ } else {
+ notifyChange(ChangeReason.DELETE)
+ }
+ }
+
+ override val name: String
+ get() = "ExampleStorage"
+
+ override fun createBackupRestoreEntities(): List<BackupRestoreEntity> =
+ listOf(StringEntity("data"))
+
+ override fun enableRestore(): Boolean {
+ return true // check condition like flag, environment, etc.
+ }
+
+ override fun enableBackup(backupContext: BackupContext): Boolean {
+ return true // check condition like flag, environment, etc.
+ }
+
+ @BinderThread
+ private inner class StringEntity(override val key: String) : BackupRestoreEntity {
+ override fun backup(backupContext: BackupContext, outputStream: OutputStream) =
+ if (data != null) {
+ outputStream.write(data!!.toByteArray(UTF_8))
+ EntityBackupResult.UPDATE
+ } else {
+ EntityBackupResult.DELETE // delete existing backup data
+ }
+
+ override fun restore(restoreContext: RestoreContext, inputStream: InputStream) {
+ // DO NOT call setData API here, which will trigger notifyChange unexpectedly.
+ // Under the hood, the datastore library will call notifyChange(ChangeReason.RESTORE)
+ // later to notify observers.
+ data = String(inputStream.readBytes(), UTF_8)
+ // Handle restored data in onRestoreFinished() callback
+ }
+ }
-For `SharedPreferences` use case, leverage the `SharedPreferencesStorage`. To
-back up other file based storage, extend the `BackupRestoreFileStorage` class.
+ override fun onRestoreFinished() {
+ // TODO: Update state with the restored data. Use this callback instead of "restore()" in
+ // case the restore action involves several entities.
+ // NOTE: The library will call notifyChange(ChangeReason.RESTORE) for you
+ }
+}
+```
-Here is an example of customized datastore, which has a string to back up:
+And this is a datastore with key value data:
```kotlin
-class MyDataStore : ObservableBackupRestoreStorage() {
- // Another option is make it a StringEntity type and maintain a String field inside StringEntity
- @Volatile // backup/restore happens on Binder thread
- var data: String? = null
- private set
-
- fun setData(data: String?) {
- this.data = data
- notifyChange(ChangeReason.UPDATE)
+class ExampleKeyValueStorage :
+ BackupRestoreStorage(), KeyedObservable<String> by KeyedDataObservable() {
+ // thread safe data structure
+ private val map = ConcurrentHashMap<String, String>()
+
+ override val name: String
+ get() = "ExampleKeyValueStorage"
+
+ fun updateData(key: String, value: String?) {
+ if (value != null) {
+ map[key] = value
+ notifyChange(ChangeReason.UPDATE)
+ } else {
+ map.remove(key)
+ notifyChange(ChangeReason.DELETE)
}
+ }
- override val name: String
- get() = "MyData"
-
- override fun createBackupRestoreEntities(): List<BackupRestoreEntity> =
- listOf(StringEntity("data"))
-
- private inner class StringEntity(override val key: String) : BackupRestoreEntity {
- override fun backup(
- backupContext: BackupContext,
- outputStream: OutputStream,
- ) =
- if (data != null) {
- outputStream.write(data!!.toByteArray(UTF_8))
- EntityBackupResult.UPDATE
- } else {
- EntityBackupResult.DELETE
- }
-
- override fun restore(restoreContext: RestoreContext, inputStream: InputStream) {
- data = String(inputStream.readAllBytes(), UTF_8)
- // NOTE: The library will call notifyChange(ChangeReason.RESTORE) for you
+ override fun createBackupRestoreEntities(): List<BackupRestoreEntity> =
+ listOf(createMapBackupRestoreEntity())
+
+ private fun createMapBackupRestoreEntity() =
+ object : BackupRestoreEntity {
+ override val key: String
+ get() = "map"
+
+ override fun backup(
+ backupContext: BackupContext,
+ outputStream: OutputStream,
+ ): EntityBackupResult {
+ // Use TreeMap to achieve predictable and stable order, so that data will not be
+ // updated to Android backup backend if there is only order change.
+ val copy = TreeMap(map)
+ if (copy.isEmpty()) return EntityBackupResult.DELETE
+ val dataOutputStream = DataOutputStream(outputStream)
+ dataOutputStream.writeInt(copy.size)
+ for ((key, value) in copy) {
+ dataOutputStream.writeUTF(key)
+ dataOutputStream.writeUTF(value)
}
- }
+ return EntityBackupResult.UPDATE
+ }
- override fun onRestoreFinished() {
- // TODO: Update state with the restored data. Use this callback instead "restore()" in case
- // the restore action involves several entities.
- // NOTE: The library will call notifyChange(ChangeReason.RESTORE) for you
+ override fun restore(restoreContext: RestoreContext, inputStream: InputStream) {
+ val dataInputString = DataInputStream(inputStream)
+ repeat(dataInputString.readInt()) {
+ val key = dataInputString.readUTF()
+ val value = dataInputString.readUTF()
+ map[key] = value
+ }
+ }
}
}
```
-In the application class:
+All the datastore should be added in the application class:
```kotlin
-class MyApplication : Application() {
+class ExampleApplication : Application() {
override fun onCreate() {
- super.onCreate();
- BackupRestoreStorageManager.getInstance(this).add(MyDataStore());
+ super.onCreate()
+ BackupRestoreStorageManager.getInstance(this)
+ .add(ExampleStorage(), ExampleKeyValueStorage())
}
}
```
-In the custom `BackupAgentHelper` class:
+Additionally, inject datastore to the custom `BackupAgentHelper` class:
```kotlin
-class MyBackupAgentHelper : BackupAgentHelper() {
+class ExampleBackupAgent : BackupAgentHelper() {
override fun onCreate() {
- BackupRestoreStorageManager.getInstance(this).addBackupAgentHelpers(this);
+ super.onCreate()
+ BackupRestoreStorageManager.getInstance(this).addBackupAgentHelpers(this)
}
override fun onRestoreFinished() {
- BackupRestoreStorageManager.getInstance(this).onRestoreFinished();
+ BackupRestoreStorageManager.getInstance(this).onRestoreFinished()
}
}
```
+
+## Development
+
+Please preserve the code coverage ratio during development. The current line
+coverage is **100% (444/444)** and branch coverage is **93.6% (176/188)**.
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreEntity.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreEntity.kt
index 817ee4c56b19..6720e5c6d714 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreEntity.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreEntity.kt
@@ -23,7 +23,11 @@ import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
-/** Entity for back up and restore. */
+/**
+ * Entity for back up and restore.
+ *
+ * Note that backup/restore callback is invoked on the binder thread.
+ */
interface BackupRestoreEntity {
/**
* Key of the entity.
@@ -45,9 +49,12 @@ interface BackupRestoreEntity {
/**
* Backs up the entity.
*
+ * Back up data in predictable order (e.g. use `TreeMap` instead of `HashMap`), otherwise data
+ * will be backed up needlessly.
+ *
* @param backupContext context for backup
* @param outputStream output stream to back up data
- * @return false if backup file is deleted, otherwise true
+ * @return backup result
*/
@BinderThread
@Throws(IOException::class)
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorage.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorage.kt
index 935f9ccf6ed9..284c97b5ad6c 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorage.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorage.kt
@@ -22,6 +22,7 @@ import android.app.backup.BackupDataOutput
import android.app.backup.BackupHelper
import android.os.ParcelFileDescriptor
import android.util.Log
+import androidx.annotation.BinderThread
import androidx.annotation.VisibleForTesting
import androidx.collection.MutableScatterMap
import com.google.common.io.ByteStreams
@@ -38,16 +39,22 @@ import java.util.zip.CRC32
import java.util.zip.CheckedInputStream
import java.util.zip.CheckedOutputStream
import java.util.zip.Checksum
+import javax.annotation.concurrent.ThreadSafe
internal const val LOG_TAG = "BackupRestoreStorage"
/**
- * Storage with backup and restore support. Subclass must implement either [Observable] or
- * [KeyedObservable] interface.
+ * Storage with backup and restore support.
+ *
+ * Subclass MUST
+ * - implement either [Observable] or [KeyedObservable] interface.
+ * - be thread safe, backup/restore happens on Binder thread, while general data read/write
+ * operations occur on other threads.
*
* The storage is identified by a unique string [name] and data set is split into entities
* ([BackupRestoreEntity]).
*/
+@ThreadSafe
abstract class BackupRestoreStorage : BackupHelper {
/**
* A unique string used to disambiguate the various storages within backup agent.
@@ -68,7 +75,7 @@ abstract class BackupRestoreStorage : BackupHelper {
@VisibleForTesting internal var entities: List<BackupRestoreEntity>? = null
/** Entities to back up and restore. */
- abstract fun createBackupRestoreEntities(): List<BackupRestoreEntity>
+ @BinderThread abstract fun createBackupRestoreEntities(): List<BackupRestoreEntity>
/** Default codec used to encode/decode the entity data. */
open fun defaultCodec(): BackupCodec = BackupZipCodec.BEST_COMPRESSION
@@ -134,7 +141,11 @@ abstract class BackupRestoreStorage : BackupHelper {
Log.i(LOG_TAG, "[$name] Backup end")
}
- /** Returns if backup is enabled. */
+ /**
+ * Returns if backup is enabled.
+ *
+ * If disabled, [performBackup] will be no-op, all entities backup are skipped.
+ */
open fun enableBackup(backupContext: BackupContext): Boolean = true
open fun wrapBackupOutputStream(codec: BackupCodec, outputStream: OutputStream): OutputStream {
@@ -172,7 +183,11 @@ abstract class BackupRestoreStorage : BackupHelper {
private fun ensureEntities(): List<BackupRestoreEntity> =
entities ?: createBackupRestoreEntities().also { entities = it }
- /** Returns if restore is enabled. */
+ /**
+ * Returns if restore is enabled.
+ *
+ * If disabled, [restoreEntity] will be no-op, all entities restore are skipped.
+ */
open fun enableRestore(): Boolean = true
open fun wrapRestoreInputStream(
@@ -188,12 +203,13 @@ abstract class BackupRestoreStorage : BackupHelper {
}
final override fun writeNewStateDescription(newState: ParcelFileDescriptor) {
+ if (!enableRestore()) return
entities = null // clear to reduce memory footprint
newState.writeAndClearEntityStates()
onRestoreFinished()
}
- /** Callbacks when restore finished. */
+ /** Callbacks when entity data are all restored. */
open fun onRestoreFinished() {}
@VisibleForTesting
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageTest.kt
index 99998ffc13ec..26534baaa47d 100644
--- a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageTest.kt
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageTest.kt
@@ -248,6 +248,15 @@ class BackupRestoreStorageTest {
}
@Test
+ fun writeNewStateDescription_restoreDisabled() {
+ val storage = spy(TestStorage().apply { enabled = false })
+ temporaryFolder.newFile().toParcelFileDescriptor(MODE_WRITE_ONLY or MODE_APPEND).use {
+ storage.writeNewStateDescription(it)
+ }
+ verify(storage, never()).onRestoreFinished()
+ }
+
+ @Test
fun backupAndRestore() {
val storage = spy(TestStorage(entity1, entity2))
val backupAgentHelper = BackupAgentHelper()
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v35/settingslib_preference_bg_color.xml b/packages/SettingsLib/SettingsTheme/res/color-v35/settingslib_preference_bg_color.xml
index 4ced9f2469ab..cece9665b729 100644
--- a/packages/SettingsLib/SettingsTheme/res/color-v35/settingslib_preference_bg_color.xml
+++ b/packages/SettingsLib/SettingsTheme/res/color-v35/settingslib_preference_bg_color.xml
@@ -16,8 +16,8 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true" android:color="@color/settingslib_materialColorSecondaryContainer"/>
- <item android:state_selected="true" android:color="@color/settingslib_materialColorSecondaryContainer"/>
- <item android:state_activated="true" android:color="@color/settingslib_materialColorSecondaryContainer"/>
- <item android:color="@color/settingslib_materialColorSurfaceContainerHighest"/> <!-- not selected -->
+ <item android:state_pressed="true" android:color="@color/settingslib_materialColorSurfaceContainerHigh"/>
+ <item android:state_selected="true" android:color="@color/settingslib_materialColorSurfaceContainerHigh"/>
+ <item android:state_activated="true" android:color="@color/settingslib_materialColorSurfaceContainerHigh"/>
+ <item android:color="@color/settingslib_materialColorSurfaceBright"/> <!-- not selected -->
</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background.xml
index 285ab7301162..eba9c2ceba70 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background.xml
@@ -19,12 +19,12 @@
<item
android:left="?android:attr/listPreferredItemPaddingStart"
android:right="?android:attr/listPreferredItemPaddingEnd"
- android:top="1dp">
+ android:top="2dp">
<shape android:shape="rectangle">
<solid
android:color="@color/settingslib_preference_bg_color" />
<corners
- android:radius="?android:attr/dialogCornerRadius" />
+ android:radius="@dimen/settingslib_preference_corner_radius" />
</shape>
</item>
</layer-list> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom.xml
index e417307edc3d..5c60f37a7244 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom.xml
@@ -19,15 +19,15 @@
<item
android:left="?android:attr/listPreferredItemPaddingStart"
android:right="?android:attr/listPreferredItemPaddingEnd"
- android:top="1dp">
+ android:top="2dp">
<shape android:shape="rectangle">
<solid
android:color="@color/settingslib_preference_bg_color" />
<corners
- android:topLeftRadius="0dp"
- android:bottomLeftRadius="?android:attr/dialogCornerRadius"
- android:topRightRadius="0dp"
- android:bottomRightRadius="?android:attr/dialogCornerRadius" />
+ android:topLeftRadius="4dp"
+ android:bottomLeftRadius="@dimen/settingslib_preference_corner_radius"
+ android:topRightRadius="4dp"
+ android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" />
</shape>
</item>
</layer-list> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml
new file mode 100644
index 000000000000..de64efd23a0d
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:left="?android:attr/listPreferredItemPaddingStart"
+ android:right="?android:attr/listPreferredItemPaddingEnd"
+ android:top="2dp">
+ <shape android:shape="rectangle">
+ <solid
+ android:color="@color/settingslib_materialColorSurfaceContainerHigh" />
+ <corners
+ android:topLeftRadius="4dp"
+ android:bottomLeftRadius="@dimen/settingslib_preference_corner_radius"
+ android:topRightRadius="4dp"
+ android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" />
+ </shape>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center.xml
index e9646575663d..dd70f4f7a146 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center.xml
@@ -19,12 +19,12 @@
<item
android:left="?android:attr/listPreferredItemPaddingStart"
android:right="?android:attr/listPreferredItemPaddingEnd"
- android:top="1dp">
+ android:top="2dp">
<shape android:shape="rectangle">
<solid
android:color="@color/settingslib_preference_bg_color" />
<corners
- android:radius="1dp" />
+ android:radius="4dp" />
</shape>
</item>
</layer-list> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml
new file mode 100644
index 000000000000..fffc6c8c4bef
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:left="?android:attr/listPreferredItemPaddingStart"
+ android:right="?android:attr/listPreferredItemPaddingEnd"
+ android:top="2dp">
+ <shape android:shape="rectangle">
+ <solid
+ android:color="@color/settingslib_materialColorSurfaceContainerHigh" />
+ <corners
+ android:radius="4dp" />
+ </shape>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml
new file mode 100644
index 000000000000..f83e3b177200
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:left="?android:attr/listPreferredItemPaddingStart"
+ android:right="?android:attr/listPreferredItemPaddingEnd"
+ android:top="2dp">
+ <shape android:shape="rectangle">
+ <solid
+ android:color="@color/settingslib_materialColorSurfaceContainerHigh" />
+ <corners
+ android:radius="@dimen/settingslib_preference_corner_radius" />
+ </shape>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top.xml
index a9d69c264a2c..ab79d18a1ab3 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top.xml
@@ -19,15 +19,15 @@
<item
android:left="?android:attr/listPreferredItemPaddingStart"
android:right="?android:attr/listPreferredItemPaddingEnd"
- android:top="1dp">
+ android:top="2dp">
<shape android:shape="rectangle">
<solid
android:color="@color/settingslib_preference_bg_color" />
<corners
- android:topLeftRadius="?android:attr/dialogCornerRadius"
- android:bottomLeftRadius="0dp"
- android:topRightRadius="?android:attr/dialogCornerRadius"
- android:bottomRightRadius="0dp" />
+ android:topLeftRadius="@dimen/settingslib_preference_corner_radius"
+ android:bottomLeftRadius="4dp"
+ android:topRightRadius="@dimen/settingslib_preference_corner_radius"
+ android:bottomRightRadius="4dp" />
</shape>
</item>
</layer-list> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml
new file mode 100644
index 000000000000..112ec735aa27
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:left="?android:attr/listPreferredItemPaddingStart"
+ android:right="?android:attr/listPreferredItemPaddingEnd"
+ android:top="2dp">
+ <shape android:shape="rectangle">
+ <solid
+ android:color="@color/settingslib_materialColorSurfaceContainerHigh" />
+ <corners
+ android:topLeftRadius="@dimen/settingslib_preference_corner_radius"
+ android:bottomLeftRadius="4dp"
+ android:topRightRadius="@dimen/settingslib_preference_corner_radius"
+ android:bottomRightRadius="4dp" />
+ </shape>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/dimens.xml
new file mode 100644
index 000000000000..d783956ee240
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <dimen name="settingslib_preference_corner_radius">20dp</dimen>
+</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 4ea746007f76..363045ec1d83 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -214,6 +214,10 @@
<string name="bluetooth_battery_level_untethered_left">Left: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery</string>
<!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for the right part of the untethered headset. [CHAR LIMIT=NONE] -->
<string name="bluetooth_battery_level_untethered_right">Right: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected, showing remote device battery level for the left part of the untethered headset. [CHAR LIMIT=NONE] -->
+ <string name="tv_bluetooth_battery_level_untethered_left">Left <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g></string>
+ <!-- Connected devices settings. Message when Bluetooth is connected, showing remote device battery level for the right part of the untethered headset. [CHAR LIMIT=NONE] -->
+ <string name="tv_bluetooth_battery_level_untethered_right">Right <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g></string>
<!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
<string name="bluetooth_active_no_battery_level">Active</string>
<!-- Connected devices settings. Message shown when bluetooth device is disconnected but is a known, previously connected device [CHAR LIMIT=NONE] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index c2a83b1e772f..0fec61c5affe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -1532,7 +1532,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
// the left.
if (leftBattery >= 0) {
String left = res.getString(
- R.string.bluetooth_battery_level_untethered_left,
+ R.string.tv_bluetooth_battery_level_untethered_left,
Utils.formatPercentage(leftBattery));
addBatterySpan(spannableBuilder, left, isBatteryLow(leftBattery,
BluetoothDevice.METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD),
@@ -1543,7 +1543,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
spannableBuilder.append(" ");
}
String right = res.getString(
- R.string.bluetooth_battery_level_untethered_right,
+ R.string.tv_bluetooth_battery_level_untethered_right,
Utils.formatPercentage(rightBattery));
addBatterySpan(spannableBuilder, right, isBatteryLow(rightBattery,
BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD),
diff --git a/packages/SettingsLib/src/com/android/settingslib/satellite/SatelliteDialogUtils.kt b/packages/SettingsLib/src/com/android/settingslib/satellite/SatelliteDialogUtils.kt
new file mode 100644
index 000000000000..d69c87b318e2
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/satellite/SatelliteDialogUtils.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 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.settingslib.satellite
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.os.OutcomeReceiver
+import android.telephony.satellite.SatelliteManager
+import android.util.Log
+import android.view.WindowManager
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import com.android.settingslib.wifi.WifiUtils
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Dispatchers.Default
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.TimeoutException
+import kotlin.coroutines.resume
+
+/** A util for Satellite dialog */
+object SatelliteDialogUtils {
+
+ /**
+ * Uses to start Satellite dialog to prevent users from using the BT, Airplane Mode, and
+ * Wifi during the satellite mode is on.
+ */
+ @JvmStatic
+ fun mayStartSatelliteWarningDialog(
+ context: Context,
+ lifecycleOwner: LifecycleOwner,
+ type: Int,
+ allowClick: (isAllowed: Boolean) -> Unit
+ ): Job {
+ return mayStartSatelliteWarningDialog(
+ context, lifecycleOwner.lifecycleScope, type, allowClick)
+ }
+
+ /**
+ * Uses to start Satellite dialog to prevent users from using the BT, Airplane Mode, and
+ * Wifi during the satellite mode is on.
+ */
+ @JvmStatic
+ fun mayStartSatelliteWarningDialog(
+ context: Context,
+ coroutineScope: CoroutineScope,
+ type: Int,
+ allowClick: (isAllowed: Boolean) -> Unit
+ ): Job =
+ coroutineScope.launch {
+ var isSatelliteModeOn = false
+ try {
+ isSatelliteModeOn = requestIsEnabled(context)
+ } catch (e: InterruptedException) {
+ Log.w(TAG, "Error to get satellite status : $e")
+ } catch (e: ExecutionException) {
+ Log.w(TAG, "Error to get satellite status : $e")
+ } catch (e: TimeoutException) {
+ Log.w(TAG, "Error to get satellite status : $e")
+ }
+
+ if (isSatelliteModeOn) {
+ startSatelliteWarningDialog(context, type)
+ }
+ withContext(Dispatchers.Main) {
+ allowClick(!isSatelliteModeOn)
+ }
+ }
+
+ private fun startSatelliteWarningDialog(context: Context, type: Int) {
+ context.startActivity(Intent(Intent.ACTION_MAIN).apply {
+ component = ComponentName(
+ "com.android.settings",
+ "com.android.settings.network.SatelliteWarningDialogActivity"
+ )
+ putExtra(WifiUtils.DIALOG_WINDOW_TYPE,
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG)
+ putExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, type)
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
+ })
+ }
+
+ /**
+ * Checks if the satellite modem is enabled.
+ *
+ * @param executor The executor to run the asynchronous operation on
+ * @return A ListenableFuture that will resolve to `true` if the satellite modem enabled,
+ * `false` otherwise.
+ */
+ private suspend fun requestIsEnabled(
+ context: Context,
+ ): Boolean = withContext(Default) {
+ val satelliteManager: SatelliteManager? =
+ context.getSystemService(SatelliteManager::class.java)
+ if (satelliteManager == null) {
+ Log.w(TAG, "SatelliteManager is null")
+ return@withContext false
+ }
+
+ suspendCancellableCoroutine {continuation ->
+ satelliteManager?.requestIsEnabled(Default.asExecutor(),
+ object : OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> {
+ override fun onResult(result: Boolean) {
+ Log.i(TAG, "Satellite modem enabled status: $result")
+ continuation.resume(result)
+ }
+
+ override fun onError(error: SatelliteManager.SatelliteException) {
+ super.onError(error)
+ Log.w(TAG, "Can't get satellite modem enabled status", error)
+ continuation.resume(false)
+ }
+ })
+ }
+ }
+
+ const val TAG = "SatelliteDialogUtils"
+
+ const val EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG: String =
+ "extra_type_of_satellite_warning_dialog"
+ const val TYPE_IS_UNKNOWN = -1
+ const val TYPE_IS_WIFI = 0
+ const val TYPE_IS_BLUETOOTH = 1
+ const val TYPE_IS_AIRPLANE_MODE = 2
+} \ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp
index f87b5190c7a1..e125083488ed 100644
--- a/packages/SettingsLib/tests/robotests/Android.bp
+++ b/packages/SettingsLib/tests/robotests/Android.bp
@@ -41,7 +41,10 @@ android_app {
//###########################################################
android_robolectric_test {
name: "SettingsLibRoboTests",
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
static_libs: [
"Settings_robolectric_meta_service_file",
"Robolectric_shadows_androidx_fragment_upstream",
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index b9bf9caddac7..0d814947527c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -780,9 +780,8 @@ public class CachedBluetoothDeviceTest {
mBatteryLevel = 10;
// Act & Assert:
- // Get "Left: 10% battery" result with Battery Level 10.
- assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo(
- "Left: 10% battery");
+ // Get "Left 10%" result with Battery Level 10.
+ assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Left 10%");
}
@Test
@@ -815,9 +814,9 @@ public class CachedBluetoothDeviceTest {
mBatteryLevel = 10;
// Act & Assert:
- // Get "Left: 10% battery" result with Battery Level 10.
+ // Get "Left 10%" result with Battery Level 10.
assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo(
- "Left: 10% battery");
+ "Left 10%");
}
@Test
@@ -925,9 +924,9 @@ public class CachedBluetoothDeviceTest {
mBatteryLevel = 10;
// Act & Assert:
- // Get "Left: 10% battery Right: 10% battery" result with Battery Level 10.
+ // Get "Left 10% Right 10%" result with Battery Level 10.
assertThat(mCachedDevice.getTvConnectionSummary().toString())
- .isEqualTo("Left: 10% battery Right: 10% battery");
+ .isEqualTo("Left 10% Right 10%");
}
@Test
@@ -1226,7 +1225,7 @@ public class CachedBluetoothDeviceTest {
TWS_BATTERY_RIGHT.getBytes());
assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo(
- "Left: 15% battery Right: 25% battery");
+ "Left 15% Right 25%");
}
@Test
@@ -1262,11 +1261,7 @@ public class CachedBluetoothDeviceTest {
TWS_BATTERY_RIGHT.getBytes());
assertThat(mCachedDevice.getTvConnectionSummary().toString())
- .isEqualTo(
- mContext.getString(R.string.bluetooth_battery_level_untethered_left, "15%")
- + " "
- + mContext.getString(
- R.string.bluetooth_battery_level_untethered_right, "25%"));
+ .isEqualTo("Left 15% Right 25%");
}
@Test
@@ -1283,10 +1278,8 @@ public class CachedBluetoothDeviceTest {
.thenReturn(TWS_BATTERY_RIGHT.getBytes());
int lowBatteryColor = mContext.getColor(LOW_BATTERY_COLOR);
- String leftBattery =
- mContext.getString(R.string.bluetooth_battery_level_untethered_left, "15%");
- String rightBattery =
- mContext.getString(R.string.bluetooth_battery_level_untethered_right, "25%");
+ String leftBattery = "Left 15%";
+ String rightBattery = "Right 25%";
// Default low battery threshold, only left battery is low
CharSequence summary = mCachedDevice.getTvConnectionSummary(LOW_BATTERY_COLOR);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt
new file mode 100644
index 000000000000..aeda1ed66d16
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2024 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.settingslib.satellite
+
+import android.content.Context
+import android.content.Intent
+import android.os.OutcomeReceiver
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.telephony.satellite.SatelliteManager
+import android.telephony.satellite.SatelliteManager.SatelliteException
+import android.util.AndroidRuntimeException
+import androidx.test.core.app.ApplicationProvider
+import com.android.internal.telephony.flags.Flags
+import com.android.settingslib.satellite.SatelliteDialogUtils.TYPE_IS_WIFI
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.`when`
+import org.mockito.Spy
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.Mockito.verify
+import org.mockito.internal.verification.Times
+import org.robolectric.RobolectricTestRunner
+
+@RunWith(RobolectricTestRunner::class)
+class SatelliteDialogUtilsTest {
+ @JvmField
+ @Rule
+ val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ @Spy
+ var context: Context = ApplicationProvider.getApplicationContext()
+ @Mock
+ private lateinit var satelliteManager: SatelliteManager
+
+ private val coroutineScope = CoroutineScope(Dispatchers.Main)
+
+ @Before
+ fun setUp() {
+ `when`(context.getSystemService(SatelliteManager::class.java))
+ .thenReturn(satelliteManager)
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun mayStartSatelliteWarningDialog_satelliteIsOn_showWarningDialog() = runBlocking {
+ `when`(
+ satelliteManager.requestIsEnabled(
+ any(), any<OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>()
+ )
+ )
+ .thenAnswer { invocation ->
+ val receiver = invocation
+ .getArgument<
+ OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>(
+ 1
+ )
+ receiver.onResult(true)
+ null
+ }
+
+ try {
+ SatelliteDialogUtils.mayStartSatelliteWarningDialog(
+ context, coroutineScope, TYPE_IS_WIFI, allowClick = {
+ assertTrue(it)
+ })
+ } catch (e: AndroidRuntimeException) {
+ // Catch exception of starting activity .
+ }
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun mayStartSatelliteWarningDialog_satelliteIsOff_notShowWarningDialog() = runBlocking {
+ `when`(
+ satelliteManager.requestIsEnabled(
+ any(), any<OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>()
+ )
+ )
+ .thenAnswer { invocation ->
+ val receiver = invocation
+ .getArgument<
+ OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>(
+ 1
+ )
+ receiver.onResult(false)
+ null
+ }
+
+
+ SatelliteDialogUtils.mayStartSatelliteWarningDialog(
+ context, coroutineScope, TYPE_IS_WIFI, allowClick = {
+ assertFalse(it)
+ })
+
+ verify(context, Times(0)).startActivity(any<Intent>())
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun mayStartSatelliteWarningDialog_noSatelliteManager_notShowWarningDialog() = runBlocking {
+ `when`(context.getSystemService(SatelliteManager::class.java))
+ .thenReturn(null)
+
+ SatelliteDialogUtils.mayStartSatelliteWarningDialog(
+ context, coroutineScope, TYPE_IS_WIFI, allowClick = {
+ assertFalse(it)
+ })
+
+ verify(context, Times(0)).startActivity(any<Intent>())
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun mayStartSatelliteWarningDialog_satelliteErrorResult_notShowWarningDialog() = runBlocking {
+ `when`(
+ satelliteManager.requestIsEnabled(
+ any(), any<OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>()
+ )
+ )
+ .thenAnswer { invocation ->
+ val receiver = invocation
+ .getArgument<
+ OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>(
+ 1
+ )
+ receiver.onError(SatelliteException(SatelliteManager.SATELLITE_RESULT_ERROR))
+ null
+ }
+
+
+ SatelliteDialogUtils.mayStartSatelliteWarningDialog(
+ context, coroutineScope, TYPE_IS_WIFI, allowClick = {
+ assertFalse(it)
+ })
+
+ verify(context, Times(0)).startActivity(any<Intent>())
+ }
+}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 46bf494f2b1a..374240bb7262 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -347,6 +347,7 @@
<uses-permission android:name="android.permission.REQUEST_COMPANION_SELF_MANAGED" />
<uses-permission android:name="android.permission.USE_COMPANION_TRANSPORTS" />
<uses-permission android:name="android.permission.REQUEST_OBSERVE_DEVICE_UUID_PRESENCE" />
+ <uses-permission android:name="android.permission.DELIVER_COMPANION_MESSAGES" />
<uses-permission android:name="android.permission.MANAGE_APPOPS" />
<uses-permission android:name="android.permission.WATCH_APPOPS" />
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index d2ca11207084..8b60ed035d07 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -87,6 +87,52 @@ filegroup {
"tests/src/**/systemui/util/sensors/AsyncManagerTest.java",
"tests/src/**/systemui/util/sensors/ThresholdSensorImplTest.java",
"tests/src/**/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java",
+ "tests/src/**/systemui/statusbar/KeyboardShortcutListSearchTest.java",
+ "tests/src/**/systemui/statusbar/KeyboardShortcutsTest.java",
+ "tests/src/**/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt",
+ "tests/src/**/systemui/statusbar/notification/AssistantFeedbackControllerTest.java",
+ "tests/src/**/systemui/statusbar/notification/collection/NotifCollectionTest.java",
+ "tests/src/**/systemui/statusbar/notification/collection/NotificationEntryTest.java",
+ "tests/src/**/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt",
+ "tests/src/**/systemui/statusbar/notification/collection/ShadeListBuilderTest.java",
+ "tests/src/**/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java",
+ "tests/src/**/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java",
+ "tests/src/**/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt",
+ "tests/src/**/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt",
+ "tests/src/**/systemui/statusbar/NotificationLockscreenUserManagerTest.java",
+ "tests/src/**/systemui/statusbar/notification/logging/NotificationLoggerTest.java",
+ "tests/src/**/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java",
+ "tests/src/**/systemui/statusbar/notification/row/NotificationContentInflaterTest.java",
+ "tests/src/**/systemui/statusbar/notification/row/NotificationContentViewTest.kt",
+ "tests/src/**/systemui/statusbar/notification/row/NotificationConversationInfoTest.java",
+ "tests/src/**/systemui/statusbar/notification/row/NotificationGutsManagerTest.java",
+ "tests/src/**/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt",
+ "tests/src/**/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt",
+ "tests/src/**/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt",
+ "tests/src/**/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java",
+ "tests/src/**/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java",
+ "tests/src/**/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt",
+ "tests/src/**/systemui/statusbar/phone/AutoTileManagerTest.java",
+ "tests/src/**/systemui/statusbar/phone/CentralSurfacesImplTest.java",
+ "tests/src/**/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java",
+ "tests/src/**/systemui/statusbar/phone/PhoneStatusBarTransitionsTest.kt",
+ "tests/src/**/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt",
+ "tests/src/**/systemui/statusbar/phone/PhoneStatusBarView.java",
+ "tests/src/**/systemui/statusbar/phone/PhoneStatusBarViewTest.kt",
+ "tests/src/**/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt",
+ "tests/src/**/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt",
+ "tests/src/**/systemui/statusbar/policy/CallbackControllerTest.java",
+ "tests/src/**/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java",
+ "tests/src/**/systemui/statusbar/policy/InflatedSmartRepliesTest.java",
+ "tests/src/**/systemui/statusbar/policy/LocationControllerImplTest.java",
+ "tests/src/**/systemui/statusbar/policy/RemoteInputViewTest.java",
+ "tests/src/**/systemui/statusbar/policy/SmartReplyViewTest.java",
+ "tests/src/**/systemui/statusbar/StatusBarStateControllerImplTest.kt",
],
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b9e70ef14007..9c58371a387d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -826,20 +826,6 @@
</intent-filter>
</activity>
- <activity
- android:name=".contrast.ContrastDialogActivity"
- android:label="@string/quick_settings_contrast_label"
- android:theme="@style/Theme.SystemUI.ContrastDialog"
- android:finishOnCloseSystemDialogs="true"
- android:launchMode="singleInstance"
- android:excludeFromRecents="true"
- android:exported="true">
- <intent-filter>
- <action android:name="com.android.intent.action.SHOW_CONTRAST_DIALOG" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
<activity android:name=".ForegroundServicesDialog"
android:process=":fgservices"
android:excludeFromRecents="true"
diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
index 755fe2a4476a..55edff6d9518 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -4,6 +4,13 @@ container: "system"
# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
flag {
+ name: "create_windowless_window_magnifier"
+ namespace: "accessibility"
+ description: "Uses SurfaceControlViewHost to create the magnifier for window magnification."
+ bug: "280992417"
+}
+
+flag {
name: "delay_show_magnification_button"
namespace: "accessibility"
description: "Delays the showing of magnification mode switch button."
@@ -66,8 +73,11 @@ flag {
}
flag {
- name: "create_windowless_window_magnifier"
+ name: "save_and_restore_magnification_settings_buttons"
namespace: "accessibility"
- description: "Uses SurfaceControlViewHost to create the magnifier for window magnification."
- bug: "280992417"
+ description: "Saves the selected button status in magnification settings and restore the status when revisiting the same smallest screen DP."
+ bug: "325567876"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index aff86e8a14c4..f9e955bf0366 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -26,14 +26,6 @@ flag {
}
flag {
-
- name: "notification_heads_up_cycling"
- namespace: "systemui"
- description: "Heads-up notification cycling animation for the Notification Avalanche feature."
- bug: "316404716"
-}
-
-flag {
name: "priority_people_section"
namespace: "systemui"
description: "Add a new section for priority people (aka important conversations)."
@@ -204,7 +196,16 @@ flag {
description: "Re-enable the codepath that removed tinting of notifications when the"
" standard background color is desired. This was the behavior before we discovered"
" a resources threading issue, which we worked around by tinting the notification"
- " backgrounds and footer buttons."
+ " backgrounds."
+ bug: "294830092"
+}
+
+flag {
+ name: "notification_footer_background_tint_optimization"
+ namespace: "systemui"
+ description: "Remove duplicative tinting of notification footer buttons. This was the behavior"
+ " before we discovered a resources threading issue, which we worked around by applying the"
+ " same color as a tint to the background drawable of footer buttons."
bug: "294830092"
}
@@ -355,6 +356,14 @@ flag {
}
flag {
+ name: "status_bar_screen_sharing_chips"
+ namespace: "systemui"
+ description: "Show chips on the left side of the status bar when a user is screen sharing, "
+ "recording, or casting"
+ bug: "332662551"
+}
+
+flag {
name: "compose_bouncer"
namespace: "systemui"
description: "Use the new compose bouncer in SystemUI"
@@ -496,6 +505,15 @@ flag {
}
}
+flag {
+ name: "screenshot_scroll_crop_view_crash_fix"
+ namespace: "systemui"
+ description: "Mitigate crash on invalid computed range in CropView"
+ bug: "232633995"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
flag {
name: "screenshot_private_profile_behavior_fix"
@@ -943,3 +961,10 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "glanceable_hub_gesture_handle"
+ namespace: "systemui"
+ description: "Shows a vertical bar at the right edge to indicate the user can swipe to open the glanceable hub"
+ bug: "339667383"
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 8ee8ea4b4f4c..feb1f5b17bef 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -2,16 +2,24 @@ package com.android.systemui.communal.ui.compose
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.ElementKey
@@ -26,6 +34,7 @@ import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.transitions
+import com.android.systemui.Flags
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.communal.ui.compose.extensions.allowGestures
@@ -88,6 +97,8 @@ fun CommunalContainer(
val currentSceneKey: SceneKey by
viewModel.currentScene.collectAsStateWithLifecycle(CommunalScenes.Blank)
val touchesAllowed by viewModel.touchesAllowed.collectAsStateWithLifecycle(initialValue = false)
+ val showGestureIndicator by
+ viewModel.showGestureIndicator.collectAsStateWithLifecycle(initialValue = false)
val state: MutableSceneTransitionLayoutState = remember {
MutableSceneTransitionLayoutState(
initialScene = currentSceneKey,
@@ -126,7 +137,19 @@ fun CommunalContainer(
)
) {
// This scene shows nothing only allowing for transitions to the communal scene.
- Box(modifier = Modifier.fillMaxSize())
+ // TODO(b/339667383): remove this temporary swipe gesture handle
+ Row(modifier = Modifier.fillMaxSize(), horizontalArrangement = Arrangement.End) {
+ if (showGestureIndicator && Flags.glanceableHubGestureHandle()) {
+ Box(
+ modifier =
+ Modifier.height(220.dp)
+ .width(4.dp)
+ .align(Alignment.CenterVertically)
+ .background(color = Color.White, RoundedCornerShape(4.dp))
+ )
+ Spacer(modifier = Modifier.width(12.dp))
+ }
+ }
}
scene(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index 6d8c47d84850..ca4ff837daa6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -24,6 +24,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
@@ -60,6 +61,6 @@ constructor(
}
val blueprint = blueprintByBlueprintId[blueprintId] ?: return
- with(blueprint) { Content(modifier) }
+ with(blueprint) { Content(modifier.sysuiResTag("keyguard_root_view")) }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index abff93d15c55..a39fa64dd45b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -31,6 +31,7 @@ import androidx.compose.ui.unit.IntRect
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
+import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
@@ -129,7 +130,7 @@ constructor(
with(lockSection) { LockIcon() }
// Aligned to bottom and constrained to below the lock icon.
- Column(modifier = Modifier.fillMaxWidth()) {
+ Column(modifier = Modifier.fillMaxWidth().sysuiResTag("keyguard_bottom_area")) {
if (isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
with(ambientIndicationSectionOptional.get()) {
AmbientIndication(modifier = Modifier.fillMaxWidth())
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index 88b8298335aa..067315381773 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -36,7 +36,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.modifiers.thenIf
-import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.largeClockScene
import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.smallClockScene
@@ -80,7 +79,7 @@ constructor(
}
SceneTransitionLayout(
- modifier = modifier.sysuiResTag("keyguard_clock_container"),
+ modifier = modifier,
currentScene = currentScene,
onChangeScene = {},
transitions = ClockTransition.defaultClockTransitions,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryImplTest.kt
index 312c14df9505..fec56ed919de 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryImplTest.kt
@@ -18,9 +18,13 @@ package com.android.systemui.brightness.data.repository
import android.content.applicationContext
import android.os.UserManager
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
+import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf
import androidx.test.filters.SmallTest
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
+import com.android.systemui.Flags.FLAG_ENFORCE_BRIGHTNESS_BASE_USER_RESTRICTION
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testDispatcher
@@ -40,14 +44,18 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class BrightnessPolicyRepositoryImplTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class BrightnessPolicyRepositoryImplTest(flags: FlagsParameterization) : SysuiTestCase() {
- private val kosmos = testKosmos()
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags)
+ }
- private val fakeUserRepository = kosmos.fakeUserRepository
+ private val kosmos = testKosmos()
private val mockUserRestrictionChecker: UserRestrictionChecker = mock {
whenever(checkIfRestrictionEnforced(any(), anyString(), anyInt())).thenReturn(null)
@@ -130,7 +138,83 @@ class BrightnessPolicyRepositoryImplTest : SysuiTestCase() {
}
}
- private companion object {
- val RESTRICTION = UserManager.DISALLOW_CONFIG_BRIGHTNESS
+ @Test
+ @DisableFlags(FLAG_ENFORCE_BRIGHTNESS_BASE_USER_RESTRICTION)
+ fun brightnessBaseUserRestriction_flagOff_noRestriction() =
+ with(kosmos) {
+ testScope.runTest {
+ whenever(
+ mockUserRestrictionChecker.hasBaseUserRestriction(
+ any(),
+ eq(RESTRICTION),
+ eq(userRepository.getSelectedUserInfo().id)
+ )
+ )
+ .thenReturn(true)
+
+ val restrictions by collectLastValue(underTest.restrictionPolicy)
+
+ assertThat(restrictions).isEqualTo(PolicyRestriction.NoRestriction)
+ }
+ }
+
+ @Test
+ fun bothRestrictions_returnsSetEnforcedAdminFromCheck() =
+ with(kosmos) {
+ testScope.runTest {
+ val enforcedAdmin: EnforcedAdmin =
+ EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(RESTRICTION)
+
+ whenever(
+ mockUserRestrictionChecker.checkIfRestrictionEnforced(
+ any(),
+ eq(RESTRICTION),
+ eq(userRepository.getSelectedUserInfo().id)
+ )
+ )
+ .thenReturn(enforcedAdmin)
+
+ whenever(
+ mockUserRestrictionChecker.hasBaseUserRestriction(
+ any(),
+ eq(RESTRICTION),
+ eq(userRepository.getSelectedUserInfo().id)
+ )
+ )
+ .thenReturn(true)
+
+ val restrictions by collectLastValue(underTest.restrictionPolicy)
+
+ assertThat(restrictions).isEqualTo(PolicyRestriction.Restricted(enforcedAdmin))
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENFORCE_BRIGHTNESS_BASE_USER_RESTRICTION)
+ fun brightnessBaseUserRestriction_flagOn_emptyRestriction() =
+ with(kosmos) {
+ testScope.runTest {
+ whenever(
+ mockUserRestrictionChecker.hasBaseUserRestriction(
+ any(),
+ eq(RESTRICTION),
+ eq(userRepository.getSelectedUserInfo().id)
+ )
+ )
+ .thenReturn(true)
+
+ val restrictions by collectLastValue(underTest.restrictionPolicy)
+
+ assertThat(restrictions).isEqualTo(PolicyRestriction.Restricted(EnforcedAdmin()))
+ }
+ }
+
+ companion object {
+ private const val RESTRICTION = UserManager.DISALLOW_CONFIG_BRIGHTNESS
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return allCombinationsOf(FLAG_ENFORCE_BRIGHTNESS_BASE_USER_RESTRICTION)
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorTest.kt
index 85a4bcf62223..11f523846268 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorTest.kt
@@ -48,7 +48,6 @@ class BrightnessPolicyEnforcementInteractorTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val mockActivityStarter = kosmos.activityStarter
- private val fakeBrightnessPolicyEnforcementInteractor = kosmos.fakeBrightnessPolicyRepository
private val underTest =
with(kosmos) {
@@ -70,7 +69,18 @@ class BrightnessPolicyEnforcementInteractorTest : SysuiTestCase() {
fakeBrightnessPolicyRepository.setCurrentUserRestricted()
- assertThat(restriction).isInstanceOf(PolicyRestriction.Restricted::class.java)
+ assertThat(restriction)
+ .isEqualTo(
+ PolicyRestriction.Restricted(
+ EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(
+ BrightnessPolicyRepository.RESTRICTION
+ )
+ )
+ )
+
+ fakeBrightnessPolicyRepository.setBaseUserRestriction()
+
+ assertThat(restriction).isEqualTo(PolicyRestriction.Restricted(EnforcedAdmin()))
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 766798c2c2c3..83227e1fc597 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -204,14 +204,14 @@ class CommunalInteractorTest : SysuiTestCase() {
}
@Test
- fun isCommunalAvailable_whenDreaming_true() =
+ fun isCommunalAvailable_whenKeyguardShowing_true() =
testScope.runTest {
val isAvailable by collectLastValue(underTest.isCommunalAvailable)
assertThat(isAvailable).isFalse()
keyguardRepository.setIsEncryptedOrLockdown(false)
userRepository.setSelectedUserInfo(mainUser)
- keyguardRepository.setDreaming(true)
+ keyguardRepository.setKeyguardShowing(true)
assertThat(isAvailable).isTrue()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 2d079d7488d0..be44339bab8d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -51,6 +51,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
@@ -141,6 +142,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
testScope,
context.resources,
kosmos.keyguardTransitionInteractor,
+ kosmos.keyguardInteractor,
kosmos.communalInteractor,
kosmos.communalTutorialInteractor,
kosmos.shadeInteractor,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 8bfa5cff8b97..f5c86e092a26 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -31,8 +31,11 @@ import android.app.DreamManager;
import android.content.res.Resources;
import android.graphics.Region;
import android.os.Handler;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper.RunWithLooper;
import android.view.AttachedSurfaceControl;
+import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
@@ -42,6 +45,7 @@ import androidx.test.filters.SmallTest;
import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.keyguard.BouncerPanelExpansionCalculator;
+import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
@@ -94,6 +98,9 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
ViewGroup mDreamOverlayContentView;
@Mock
+ View mHubGestureIndicatorView;
+
+ @Mock
Handler mHandler;
@Mock
@@ -142,6 +149,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mDreamOverlayContainerView,
mComplicationHostViewController,
mDreamOverlayContentView,
+ mHubGestureIndicatorView,
mDreamOverlayStatusBarViewController,
mLowLightTransitionCoordinator,
mBlurUtils,
@@ -161,6 +169,18 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mDreamManager);
}
+ @DisableFlags(Flags.FLAG_COMMUNAL_HUB)
+ @Test
+ public void testHubGestureIndicatorGoneWhenFlagOff() {
+ verify(mHubGestureIndicatorView, never()).setVisibility(View.VISIBLE);
+ }
+
+ @EnableFlags({Flags.FLAG_COMMUNAL_HUB, Flags.FLAG_GLANCEABLE_HUB_GESTURE_HANDLE})
+ @Test
+ public void testHubGestureIndicatorVisibleWhenFlagOn() {
+ verify(mHubGestureIndicatorView).setVisibility(View.VISIBLE);
+ }
+
@Test
public void testRootSurfaceControlInsetSetOnAttach() {
mController.onViewAttached();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/FingerprintPropertyRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/FingerprintPropertyRepositoryTest.kt
new file mode 100644
index 000000000000..1e7ed6316f7f
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/FingerprintPropertyRepositoryTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.data.repository
+
+import android.hardware.fingerprint.FingerprintManager
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepositoryImpl
+import com.android.systemui.coroutines.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@ExperimentalCoroutinesApi
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class FingerprintPropertyRepositoryTest : SysuiTestCase() {
+ @JvmField @Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+ private val testScope = TestScope()
+ private lateinit var underTest: FingerprintPropertyRepositoryImpl
+ @Mock private lateinit var fingerprintManager: FingerprintManager
+ @Captor
+ private lateinit var fingerprintCallbackCaptor:
+ ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback>
+
+ @Before
+ fun setup() {
+ underTest =
+ FingerprintPropertyRepositoryImpl(
+ testScope.backgroundScope,
+ Dispatchers.Main.immediate,
+ fingerprintManager,
+ )
+ }
+
+ @Test
+ fun propertiesInitialized_onStartFalse() =
+ testScope.runTest {
+ val propertiesInitialized by collectLastValue(underTest.propertiesInitialized)
+ assertThat(propertiesInitialized).isFalse()
+ }
+
+ @Test
+ fun propertiesInitialized_onStartTrue() =
+ testScope.runTest {
+ // // collect sensorType to update fingerprintCallback before
+ // propertiesInitialized
+ // // is listened for
+ val sensorType by collectLastValue(underTest.sensorType)
+ runCurrent()
+ captureFingerprintCallback()
+
+ fingerprintCallbackCaptor.value.onAllAuthenticatorsRegistered(emptyList())
+ val propertiesInitialized by collectLastValue(underTest.propertiesInitialized)
+ assertThat(propertiesInitialized).isTrue()
+ }
+
+ @Test
+ fun propertiesInitialized_updatedToTrue() =
+ testScope.runTest {
+ val propertiesInitialized by collectLastValue(underTest.propertiesInitialized)
+ assertThat(propertiesInitialized).isFalse()
+
+ captureFingerprintCallback()
+ fingerprintCallbackCaptor.value.onAllAuthenticatorsRegistered(emptyList())
+ assertThat(propertiesInitialized).isTrue()
+ }
+
+ private fun captureFingerprintCallback() {
+ verify(fingerprintManager)
+ .addAuthenticatorsRegisteredCallback(fingerprintCallbackCaptor.capture())
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
index 4226a9d89ad1..0551bfb89865 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
@@ -109,7 +109,7 @@ class MediaCarouselViewModelTest : SysuiTestCase() {
assertThat(mediaControl2.instanceId).isEqualTo(instanceId2)
assertThat(mediaControl1.instanceId).isEqualTo(instanceId1)
- underTest.onAttached()
+ underTest.onReorderingAllowed()
mediaControl1 = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl
mediaControl2 = sortedMedia?.get(1) as MediaCommonViewModel.MediaControl
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
index bf48784407b8..02a81419ea78 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
@@ -69,6 +69,15 @@ class QSTileIntentUserInputHandlerTest : SysuiTestCase() {
}
@Test
+ fun testPassesIntentToStarter_dismissShadeAndShowOverLockScreenWhenLocked() {
+ val intent = Intent("test.ACTION")
+
+ underTest.handle(null, intent, true)
+
+ verify(activityStarter).startActivity(eq(intent), eq(true), any(), eq(true))
+ }
+
+ @Test
fun testPassesActivityPendingIntentToStarterAsPendingIntent() {
val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractorTest.kt
new file mode 100644
index 000000000000..c41ce2f7854c
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractorTest.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.qr.domain.interactor
+
+import android.content.Intent
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
+import com.android.systemui.qrcodescanner.controller.QRCodeScannerController.Callback
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.impl.qr.domain.model.QRCodeScannerTileModel
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class QRCodeScannerTileDataInteractorTest : SysuiTestCase() {
+
+ private val testUser = UserHandle.of(1)!!
+ private val testDispatcher = StandardTestDispatcher()
+ private val scope = TestScope(testDispatcher)
+ private val testIntent = mock<Intent>()
+ private val qrCodeScannerController =
+ mock<QRCodeScannerController> {
+ whenever(intent).thenReturn(testIntent)
+ whenever(isAbleToLaunchScannerActivity).thenReturn(false)
+ }
+ private val testAvailableModel = QRCodeScannerTileModel.Available(testIntent)
+ private val testUnavailableModel = QRCodeScannerTileModel.TemporarilyUnavailable
+
+ private val underTest: QRCodeScannerTileDataInteractor =
+ QRCodeScannerTileDataInteractor(
+ testDispatcher,
+ scope.backgroundScope,
+ qrCodeScannerController,
+ )
+
+ @Test
+ fun availability_matchesController_cameraNotAvailable() =
+ scope.runTest {
+ val expectedAvailability = false
+ whenever(qrCodeScannerController.isCameraAvailable).thenReturn(false)
+
+ val availability by collectLastValue(underTest.availability(testUser))
+
+ assertThat(availability).isEqualTo(expectedAvailability)
+ }
+
+ @Test
+ fun availability_matchesController_cameraIsAvailable() =
+ scope.runTest {
+ val expectedAvailability = true
+ whenever(qrCodeScannerController.isCameraAvailable).thenReturn(true)
+
+ val availability by collectLastValue(underTest.availability(testUser))
+
+ assertThat(availability).isEqualTo(expectedAvailability)
+ }
+
+ @Test
+ fun data_matchesController() =
+ scope.runTest {
+ val captor = argumentCaptor<Callback>()
+ val lastData by
+ collectLastValue(
+ underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest))
+ )
+ runCurrent()
+
+ verify(qrCodeScannerController).addCallback(captor.capture())
+ val callback = captor.value
+
+ assertThat(lastData!!).isEqualTo(testUnavailableModel)
+
+ whenever(qrCodeScannerController.isAbleToLaunchScannerActivity).thenReturn(true)
+ callback.onQRCodeScannerActivityChanged()
+ runCurrent()
+ assertThat(lastData!!).isEqualTo(testAvailableModel)
+
+ whenever(qrCodeScannerController.isAbleToLaunchScannerActivity).thenReturn(false)
+ callback.onQRCodeScannerActivityChanged()
+ runCurrent()
+ assertThat(lastData!!).isEqualTo(testUnavailableModel)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractorTest.kt
new file mode 100644
index 000000000000..312f18029570
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractorTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.qr.domain.interactor
+
+import android.content.Intent
+import android.platform.test.annotations.EnabledOnRavenwood
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
+import com.android.systemui.qs.tiles.base.actions.qsTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
+import com.android.systemui.qs.tiles.impl.qr.domain.model.QRCodeScannerTileModel
+import com.android.systemui.qs.tiles.impl.qr.qrCodeScannerTileUserActionInteractor
+import com.android.systemui.util.mockito.mock
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@EnabledOnRavenwood
+@RunWith(AndroidJUnit4::class)
+class QRCodeScannerTileUserActionInteractorTest : SysuiTestCase() {
+ val kosmos = Kosmos()
+ private val inputHandler = kosmos.qsTileIntentUserInputHandler
+ private val underTest = kosmos.qrCodeScannerTileUserActionInteractor
+ private val intent = mock<Intent>()
+
+ @Test
+ fun handleClick_available() = runTest {
+ val inputModel = QRCodeScannerTileModel.Available(intent)
+
+ underTest.handleInput(QSTileInputTestKtx.click(inputModel))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ intent
+ }
+ }
+
+ @Test
+ fun handleClick_temporarilyUnavailable() = runTest {
+ val inputModel = QRCodeScannerTileModel.TemporarilyUnavailable
+
+ underTest.handleInput(QSTileInputTestKtx.click(inputModel))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledNoInputs()
+ }
+
+ @Test
+ fun handleLongClick_available() = runTest {
+ val inputModel = QRCodeScannerTileModel.Available(intent)
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(inputModel))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledNoInputs()
+ }
+
+ @Test
+ fun handleLongClick_temporarilyUnavailable() = runTest {
+ val inputModel = QRCodeScannerTileModel.TemporarilyUnavailable
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(inputModel))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledNoInputs()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapperTest.kt
new file mode 100644
index 000000000000..d26a21365f54
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapperTest.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.qr.ui
+
+import android.content.Intent
+import android.graphics.drawable.TestStubDrawable
+import android.widget.Switch
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
+import com.android.systemui.qs.tiles.impl.qr.domain.model.QRCodeScannerTileModel
+import com.android.systemui.qs.tiles.impl.qr.qsQRCodeScannerTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class QRCodeScannerTileMapperTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val config = kosmos.qsQRCodeScannerTileConfig
+
+ private lateinit var mapper: QRCodeScannerTileMapper
+
+ @Before
+ fun setup() {
+ mapper =
+ QRCodeScannerTileMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(
+ com.android.systemui.res.R.drawable.ic_qr_code_scanner,
+ TestStubDrawable()
+ )
+ }
+ .resources,
+ context.theme
+ )
+ }
+
+ @Test
+ fun availableModel() {
+ val mockIntent = mock<Intent>()
+ val inputModel = QRCodeScannerTileModel.Available(mockIntent)
+
+ val outputState = mapper.map(config, inputModel)
+
+ val expectedState =
+ createQRCodeScannerTileState(
+ QSTileState.ActivationState.INACTIVE,
+ null,
+ )
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun temporarilyUnavailableModel() {
+ val inputModel = QRCodeScannerTileModel.TemporarilyUnavailable
+
+ val outputState = mapper.map(config, inputModel)
+
+ val expectedState =
+ createQRCodeScannerTileState(
+ QSTileState.ActivationState.UNAVAILABLE,
+ context.getString(
+ com.android.systemui.res.R.string.qr_code_scanner_updating_secondary_label
+ )
+ )
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ private fun createQRCodeScannerTileState(
+ activationState: QSTileState.ActivationState,
+ secondaryLabel: String?,
+ ): QSTileState {
+ val label = context.getString(com.android.systemui.res.R.string.qr_code_scanner_title)
+ return QSTileState(
+ {
+ Icon.Loaded(
+ context.getDrawable(com.android.systemui.res.R.drawable.ic_qr_code_scanner)!!,
+ null
+ )
+ },
+ label,
+ activationState,
+ secondaryLabel,
+ setOf(QSTileState.UserAction.CLICK),
+ label,
+ null,
+ QSTileState.SideViewIcon.Chevron,
+ QSTileState.EnabledState.ENABLED,
+ Switch::class.qualifiedName
+ )
+ }
+}
diff --git a/packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml b/packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml
index a751f58344a9..370677ac0890 100644
--- a/packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml
+++ b/packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml
@@ -16,5 +16,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/material_dynamic_neutral20" />
- <corners android:radius="@dimen/ongoing_call_chip_corner_radius" />
+ <corners android:radius="@dimen/ongoing_activity_chip_corner_radius" />
</shape>
diff --git a/packages/SystemUI/res/drawable/contrast_dialog_button_background.xml b/packages/SystemUI/res/drawable/contrast_dialog_button_background.xml
deleted file mode 100644
index 4181220ed68c..000000000000
--- a/packages/SystemUI/res/drawable/contrast_dialog_button_background.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* 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.
-*/
--->
-<selector
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-
- <item android:state_selected="true">
- <shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurfaceHighlight" />
- <stroke
- android:color="?androidprv:attr/colorAccentPrimary"
- android:width="@dimen/contrast_dialog_button_stroke_width" />
- <corners android:radius="@dimen/contrast_dialog_button_radius"/>
- </shape>
- </item>
-
- <item>
- <layer-list>
- <item android:top="@dimen/contrast_dialog_button_stroke_width"
- android:bottom="@dimen/contrast_dialog_button_stroke_width"
- android:left="@dimen/contrast_dialog_button_stroke_width"
- android:right="@dimen/contrast_dialog_button_stroke_width">
- <shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurfaceHighlight" />
- <corners android:radius="@dimen/contrast_dialog_button_radius"/>
- </shape>
- </item>
- </layer-list>
- </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/hub_handle.xml b/packages/SystemUI/res/drawable/hub_handle.xml
new file mode 100644
index 000000000000..8bc276ffed9e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/hub_handle.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="4dp" />
+ <solid android:color="#FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_contrast_high.xml b/packages/SystemUI/res/drawable/ic_contrast_high.xml
deleted file mode 100644
index aa5b5abc33aa..000000000000
--- a/packages/SystemUI/res/drawable/ic_contrast_high.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<vector android:autoMirrored="true" android:height="20dp"
- android:viewportHeight="20" android:viewportWidth="66"
- android:width="66dp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="#F2F1E8"
- android:pathData="M0.5,8C0.5,3.858 3.858,0.5 8,0.5H58C62.142,0.5 65.5,3.858 65.5,8V12C65.5,16.142 62.142,19.5 58,19.5H8C3.858,19.5 0.5,16.142 0.5,12V8Z"
- android:strokeColor="#1B1C17" android:strokeWidth="1"/>
- <path android:fillColor="#1B1C17" android:pathData="M11,10m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"/>
- <path android:fillColor="#1B1C17" android:pathData="M23,5L43,5A2,2 0,0 1,45 7L45,7A2,2 0,0 1,43 9L23,9A2,2 0,0 1,21 7L21,7A2,2 0,0 1,23 5z"/>
- <path android:fillColor="#1B1C17" android:pathData="M23,11L55,11A2,2 0,0 1,57 13L57,13A2,2 0,0 1,55 15L23,15A2,2 0,0 1,21 13L21,13A2,2 0,0 1,23 11z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_contrast_medium.xml b/packages/SystemUI/res/drawable/ic_contrast_medium.xml
deleted file mode 100644
index 89519b86b974..000000000000
--- a/packages/SystemUI/res/drawable/ic_contrast_medium.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<vector android:autoMirrored="true" android:height="20dp"
- android:viewportHeight="20" android:viewportWidth="66"
- android:width="66dp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="#F2F1E8" android:pathData="M0,8C0,3.582 3.582,0 8,0H58C62.418,0 66,3.582 66,8V12C66,16.418 62.418,20 58,20H8C3.582,20 0,16.418 0,12V8Z"/>
- <path android:fillColor="#919283" android:pathData="M11,10m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"/>
- <path android:fillColor="#919283" android:pathData="M23,5L43,5A2,2 0,0 1,45 7L45,7A2,2 0,0 1,43 9L23,9A2,2 0,0 1,21 7L21,7A2,2 0,0 1,23 5z"/>
- <path android:fillColor="#919283" android:pathData="M23,11L55,11A2,2 0,0 1,57 13L57,13A2,2 0,0 1,55 15L23,15A2,2 0,0 1,21 13L21,13A2,2 0,0 1,23 11z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_contrast_standard.xml b/packages/SystemUI/res/drawable/ic_contrast_standard.xml
deleted file mode 100644
index f914975823da..000000000000
--- a/packages/SystemUI/res/drawable/ic_contrast_standard.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<vector android:autoMirrored="true" android:height="20dp"
- android:viewportHeight="20" android:viewportWidth="66"
- android:width="66dp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="#C7C8B7" android:pathData="M0,8C0,3.582 3.582,0 8,0H58C62.418,0 66,3.582 66,8V12C66,16.418 62.418,20 58,20H8C3.582,20 0,16.418 0,12V8Z"/>
- <path android:fillColor="#919283" android:pathData="M11,10m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"/>
- <path android:fillColor="#919283" android:pathData="M23,5L43,5A2,2 0,0 1,45 7L45,7A2,2 0,0 1,43 9L23,9A2,2 0,0 1,21 7L21,7A2,2 0,0 1,23 5z"/>
- <path android:fillColor="#919283" android:pathData="M23,11L55,11A2,2 0,0 1,57 13L57,13A2,2 0,0 1,55 15L23,15A2,2 0,0 1,21 13L21,13A2,2 0,0 1,23 11z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml b/packages/SystemUI/res/drawable/ongoing_activity_chip_bg.xml
index bdd6270bb50b..b9a4cbfc683e 100644
--- a/packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml
+++ b/packages/SystemUI/res/drawable/ongoing_activity_chip_bg.xml
@@ -16,5 +16,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?android:attr/colorAccent" />
- <corners android:radius="@dimen/ongoing_call_chip_corner_radius" />
+ <corners android:radius="@dimen/ongoing_activity_chip_corner_radius" />
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
index 5755dcd70a82..01b9f7e2e38a 100644
--- a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
@@ -26,8 +26,8 @@ android:layout_height="match_parent">
android:paddingVertical="16dp"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/rightGuideline"
- app:layout_constraintStart_toStartOf="@+id/leftGuideline"
+ app:layout_constraintRight_toLeftOf="@+id/rightGuideline"
+ app:layout_constraintLeft_toLeftOf="@+id/leftGuideline"
app:layout_constraintTop_toTopOf="@+id/topGuideline" />
<com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
@@ -35,8 +35,8 @@ android:layout_height="match_parent">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars" />
@@ -63,8 +63,8 @@ android:layout_height="match_parent">
android:paddingTop="24dp"
android:fadeScrollbars="false"
app:layout_constraintBottom_toTopOf="@+id/button_bar"
- app:layout_constraintEnd_toStartOf="@+id/midGuideline"
- app:layout_constraintStart_toStartOf="@id/leftGuideline"
+ app:layout_constraintRight_toLeftOf="@+id/midGuideline"
+ app:layout_constraintLeft_toLeftOf="@id/leftGuideline"
app:layout_constraintTop_toTopOf="@+id/topGuideline">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -89,7 +89,7 @@ android:layout_height="match_parent">
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
- android:paddingLeft="16dp"
+ android:paddingStart="16dp"
app:layout_constraintBottom_toBottomOf="@+id/logo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/logo"
@@ -209,6 +209,7 @@ android:layout_height="match_parent">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
+ app:guidelineUseRtl="false"
app:layout_constraintGuide_begin="@dimen/biometric_dialog_border_padding" />
<androidx.constraintlayout.widget.Guideline
@@ -216,6 +217,7 @@ android:layout_height="match_parent">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
+ app:guidelineUseRtl="false"
app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" />
<androidx.constraintlayout.widget.Guideline
@@ -223,6 +225,7 @@ android:layout_height="match_parent">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
+ app:guidelineUseRtl="false"
app:layout_constraintGuide_begin="406dp" />
<androidx.constraintlayout.widget.Guideline
diff --git a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
index 4d2310a2a6ca..0bbe73c36fc7 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
@@ -27,7 +27,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="24dp"
+ android:layout_marginStart="24dp"
android:ellipsize="end"
android:maxLines="2"
android:visibility="invisible"
@@ -41,7 +41,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="24dp"
+ android:layout_marginStart="24dp"
android:text="@string/cancel"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
@@ -54,7 +54,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="24dp"
+ android:layout_marginStart="24dp"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
@@ -66,7 +66,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginRight="24dp"
+ android:layout_marginEnd="24dp"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/biometric_dialog_confirm"
@@ -81,7 +81,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginRight="24dp"
+ android:layout_marginEnd="24dp"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/biometric_dialog_try_again"
diff --git a/packages/SystemUI/res/layout/contrast_dialog.xml b/packages/SystemUI/res/layout/contrast_dialog.xml
deleted file mode 100644
index 8e885cf39e2b..000000000000
--- a/packages/SystemUI/res/layout/contrast_dialog.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <FrameLayout
- android:id="@+id/contrast_button_standard"
- android:layout_width="@dimen/contrast_dialog_button_total_size"
- android:layout_height="@dimen/contrast_dialog_button_total_size"
- android:background="@drawable/contrast_dialog_button_background">
-
- <ImageView
- android:layout_gravity="center"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:src="@drawable/ic_contrast_standard"/>
- </FrameLayout>
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/contrast_dialog_button_text_spacing"
- android:gravity="center_horizontal|top"
- android:textSize="@dimen/contrast_dialog_button_text_size"
- android:text="@string/quick_settings_contrast_standard"
- android:textColor="?androidprv:attr/textColorPrimary"/>
- </LinearLayout>
-
- <Space
- android:layout_width="@dimen/contrast_dialog_button_horizontal_spacing"
- android:layout_height="match_parent" />
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <FrameLayout
- android:id="@+id/contrast_button_medium"
- android:layout_width="@dimen/contrast_dialog_button_total_size"
- android:layout_height="@dimen/contrast_dialog_button_total_size"
- android:background="@drawable/contrast_dialog_button_background">
-
- <ImageView
- android:layout_gravity="center"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:src="@drawable/ic_contrast_medium"/>
- </FrameLayout>
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/contrast_dialog_button_text_spacing"
- android:gravity="center_horizontal|top"
- android:textSize="@dimen/contrast_dialog_button_text_size"
- android:text="@string/quick_settings_contrast_medium"
- android:textColor="?androidprv:attr/textColorPrimary"/>
- </LinearLayout>
-
- <Space
- android:layout_width="@dimen/contrast_dialog_button_horizontal_spacing"
- android:layout_height="match_parent" />
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <FrameLayout
- android:id="@+id/contrast_button_high"
- android:layout_width="@dimen/contrast_dialog_button_total_size"
- android:layout_height="@dimen/contrast_dialog_button_total_size"
- android:background="@drawable/contrast_dialog_button_background">
-
- <ImageView
- android:layout_gravity="center"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:src="@drawable/ic_contrast_high"/>
-
- </FrameLayout>
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/contrast_dialog_button_text_spacing"
- android:gravity="center_horizontal|top"
- android:textSize="@dimen/contrast_dialog_button_text_size"
- android:text="@string/quick_settings_contrast_high"
- android:textColor="?androidprv:attr/textColorPrimary"/>
- </LinearLayout>
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml
index 19fb874ea2be..4234fca55e3c 100644
--- a/packages/SystemUI/res/layout/dream_overlay_container.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_container.xml
@@ -21,6 +21,19 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <ImageView
+ android:id="@+id/glanceable_hub_handle"
+ android:layout_width="4dp"
+ android:layout_height="220dp"
+ android:layout_centerVertical="true"
+ android:layout_marginEnd="12dp"
+ android:background="@drawable/hub_handle"
+ android:visibility="gone"
+ android:contentDescription="UI indicator for swiping open the glanceable hub"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/dream_overlay_content"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
index 6a0217ec5fe8..a33be12a655a 100644
--- a/packages/SystemUI/res/layout/ongoing_call_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
@@ -17,43 +17,45 @@
the chip. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/ongoing_call_chip"
+ android:id="@+id/ongoing_activity_chip"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="5dp"
>
- <com.android.systemui.statusbar.phone.ongoingcall.OngoingCallBackgroundContainer
- android:id="@+id/ongoing_call_chip_background"
+ <!-- TODO(b/332662551): Update this content description when this supports more than just
+ phone calls. -->
+ <com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
+ android:id="@+id/ongoing_activity_chip_background"
android:layout_width="wrap_content"
android:layout_height="@dimen/ongoing_appops_chip_height"
android:layout_gravity="center_vertical"
android:gravity="center"
- android:background="@drawable/ongoing_call_chip_bg"
- android:paddingStart="@dimen/ongoing_call_chip_side_padding"
- android:paddingEnd="@dimen/ongoing_call_chip_side_padding"
+ android:background="@drawable/ongoing_activity_chip_bg"
+ android:paddingStart="@dimen/ongoing_activity_chip_side_padding"
+ android:paddingEnd="@dimen/ongoing_activity_chip_side_padding"
android:contentDescription="@string/ongoing_phone_call_content_description"
android:minWidth="@dimen/min_clickable_item_size"
>
<ImageView
android:src="@*android:drawable/ic_phone"
- android:layout_width="@dimen/ongoing_call_chip_icon_size"
- android:layout_height="@dimen/ongoing_call_chip_icon_size"
+ android:layout_width="@dimen/ongoing_activity_chip_icon_size"
+ android:layout_height="@dimen/ongoing_activity_chip_icon_size"
android:tint="?android:attr/colorPrimary"
/>
- <com.android.systemui.statusbar.phone.ongoingcall.OngoingCallChronometer
- android:id="@+id/ongoing_call_chip_time"
+ <com.android.systemui.statusbar.chips.ui.view.ChipChronometer
+ android:id="@+id/ongoing_activity_chip_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="center|start"
- android:paddingStart="@dimen/ongoing_call_chip_icon_text_padding"
+ android:paddingStart="@dimen/ongoing_activity_chip_icon_text_padding"
android:textAppearance="@android:style/TextAppearance.Material.Small"
android:fontFamily="@*android:string/config_headlineFontFamily"
android:textColor="?android:attr/colorPrimary"
/>
- </com.android.systemui.statusbar.phone.ongoingcall.OngoingCallBackgroundContainer>
+ </com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 452bc317e2d5..4247c7eef0d0 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -99,7 +99,7 @@
android:gravity="center_vertical|start"
/>
- <include layout="@layout/ongoing_call_chip" />
+ <include layout="@layout/ongoing_activity_chip" />
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 873ddd0179bf..9d0319c2471b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1713,12 +1713,12 @@
<dimen name="wallet_button_horizontal_padding">24dp</dimen>
<dimen name="wallet_button_vertical_padding">8dp</dimen>
- <!-- Ongoing call chip -->
- <dimen name="ongoing_call_chip_side_padding">12dp</dimen>
- <dimen name="ongoing_call_chip_icon_size">16dp</dimen>
+ <!-- Ongoing activity chip -->
+ <dimen name="ongoing_activity_chip_side_padding">12dp</dimen>
+ <dimen name="ongoing_activity_chip_icon_size">16dp</dimen>
<!-- The padding between the icon and the text. -->
- <dimen name="ongoing_call_chip_icon_text_padding">4dp</dimen>
- <dimen name="ongoing_call_chip_corner_radius">28dp</dimen>
+ <dimen name="ongoing_activity_chip_icon_text_padding">4dp</dimen>
+ <dimen name="ongoing_activity_chip_corner_radius">28dp</dimen>
<!-- Status bar user chip -->
<dimen name="status_bar_user_chip_avatar_size">16dp</dimen>
@@ -1963,15 +1963,6 @@
<dimen name="broadcast_dialog_btn_minHeight">44dp</dimen>
<dimen name="broadcast_dialog_margin">16dp</dimen>
- <!-- Contrast dialog -->
- <dimen name="contrast_dialog_button_total_size">90dp</dimen>
- <dimen name="contrast_dialog_button_inner_size">82dp</dimen>
- <dimen name="contrast_dialog_button_radius">20dp</dimen>
- <dimen name="contrast_dialog_button_stroke_width">4dp</dimen>
- <dimen name="contrast_dialog_button_text_size">14sp</dimen>
- <dimen name="contrast_dialog_button_text_spacing">4dp</dimen>
- <dimen name="contrast_dialog_button_horizontal_spacing">16dp</dimen>
-
<!-- Shadow for dream overlay clock complication -->
<dimen name="dream_overlay_clock_key_text_shadow_dx">0dp</dimen>
<dimen name="dream_overlay_clock_key_text_shadow_dy">0dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index aecc9066b552..8da8316f624b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -902,15 +902,6 @@
<!-- QuickSettings: Label for the toggle that controls whether One-handed mode is enabled. [CHAR LIMIT=NONE] -->
<string name="quick_settings_onehanded_label">One-handed mode</string>
- <!-- QuickSettings: Contrast tile [CHAR LIMIT=NONE] -->
- <string name="quick_settings_contrast_label">Contrast</string>
- <!-- QuickSettings: Contrast tile description: standard [CHAR LIMIT=NONE] -->
- <string name="quick_settings_contrast_standard">Standard</string>
- <!-- QuickSettings: Contrast tile description: medium [CHAR LIMIT=NONE] -->
- <string name="quick_settings_contrast_medium">Medium</string>
- <!-- QuickSettings: Contrast tile description: high [CHAR LIMIT=NONE] -->
- <string name="quick_settings_contrast_high">High</string>
-
<!-- Hearing devices -->
<!-- QuickSettings: Hearing devices [CHAR LIMIT=NONE] -->
<string name="quick_settings_hearing_devices_label">Hearing devices</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2c4cdb9ee796..393a1aaec74a 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -523,10 +523,6 @@
<item name="android:windowExitAnimation">@anim/instant_fade_out</item>
</style>
- <style name="Theme.SystemUI.ContrastDialog" parent="@android:style/Theme.DeviceDefault.Dialog">
- <item name="android:windowBackground">@android:color/transparent</item>
- </style>
-
<style name="Theme.SystemUI.QuickSettings.Dialog" parent="@style/Theme.SystemUI.Dialog.QuickSettings">
</style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
deleted file mode 100644
index 0b0df833e916..000000000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.systemui.shared.recents.model;
-
-import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
-import static android.graphics.Bitmap.Config.ARGB_8888;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.hardware.HardwareBuffer;
-import android.util.Log;
-import android.view.WindowInsetsController.Appearance;
-import android.window.TaskSnapshot;
-
-import java.util.HashMap;
-
-/**
- * Data for a single thumbnail.
- */
-public class ThumbnailData {
-
- public final Bitmap thumbnail;
- public int orientation;
- public int rotation;
- public Rect insets;
- public Rect letterboxInsets;
- public boolean reducedResolution;
- public boolean isRealSnapshot;
- public boolean isTranslucent;
- public int windowingMode;
- public @Appearance int appearance;
- public float scale;
- public long snapshotId;
-
- public ThumbnailData() {
- thumbnail = null;
- orientation = ORIENTATION_UNDEFINED;
- rotation = ROTATION_UNDEFINED;
- insets = new Rect();
- letterboxInsets = new Rect();
- reducedResolution = false;
- scale = 1f;
- isRealSnapshot = true;
- isTranslucent = false;
- windowingMode = WINDOWING_MODE_UNDEFINED;
- snapshotId = 0;
- }
-
- public void recycleBitmap() {
- if (thumbnail != null) {
- thumbnail.recycle();
- }
- }
-
- private static Bitmap makeThumbnail(TaskSnapshot snapshot) {
- Bitmap thumbnail = null;
- try (final HardwareBuffer buffer = snapshot.getHardwareBuffer()) {
- if (buffer != null) {
- thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.getColorSpace());
- }
- } catch (IllegalArgumentException ex) {
- // TODO(b/157562905): Workaround for a crash when we get a snapshot without this state
- Log.e("ThumbnailData", "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE: "
- + snapshot.getHardwareBuffer(), ex);
- }
- if (thumbnail == null) {
- Point taskSize = snapshot.getTaskSize();
- thumbnail = Bitmap.createBitmap(taskSize.x, taskSize.y, ARGB_8888);
- thumbnail.eraseColor(Color.BLACK);
- }
- return thumbnail;
- }
-
- public static HashMap<Integer, ThumbnailData> wrap(int[] taskIds, TaskSnapshot[] snapshots) {
- HashMap<Integer, ThumbnailData> temp = new HashMap<>();
- if (taskIds == null || snapshots == null || taskIds.length != snapshots.length) {
- return temp;
- }
-
- for (int i = snapshots.length - 1; i >= 0; i--) {
- temp.put(taskIds[i], new ThumbnailData(snapshots[i]));
- }
- return temp;
- }
-
- public ThumbnailData(TaskSnapshot snapshot) {
- thumbnail = makeThumbnail(snapshot);
- insets = new Rect(snapshot.getContentInsets());
- letterboxInsets = new Rect(snapshot.getLetterboxInsets());
- orientation = snapshot.getOrientation();
- rotation = snapshot.getRotation();
- reducedResolution = snapshot.isLowResolution();
- // TODO(b/149579527): Pass task size instead of computing scale.
- // Assume width and height were scaled the same; compute scale only for width
- scale = (float) thumbnail.getWidth() / snapshot.getTaskSize().x;
- isRealSnapshot = snapshot.isRealSnapshot();
- isTranslucent = snapshot.isTranslucent();
- windowingMode = snapshot.getWindowingMode();
- appearance = snapshot.getAppearance();
- snapshotId = snapshot.getId();
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.kt
new file mode 100644
index 000000000000..dcf7754221bb
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.kt
@@ -0,0 +1,101 @@
+/*
+ * 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.systemui.shared.recents.model
+
+import android.app.WindowConfiguration
+import android.content.res.Configuration
+import android.graphics.Bitmap
+import android.graphics.Bitmap.Config.ARGB_8888
+import android.graphics.Color
+import android.graphics.Rect
+import android.util.Log
+import android.view.WindowInsetsController.Appearance
+import android.window.TaskSnapshot
+
+/** Data for a single thumbnail. */
+data class ThumbnailData(
+ val thumbnail: Bitmap? = null,
+ var orientation: Int = Configuration.ORIENTATION_UNDEFINED,
+ @JvmField var rotation: Int = WindowConfiguration.ROTATION_UNDEFINED,
+ @JvmField var insets: Rect = Rect(),
+ @JvmField var letterboxInsets: Rect = Rect(),
+ @JvmField var reducedResolution: Boolean = false,
+ @JvmField var isRealSnapshot: Boolean = true,
+ var isTranslucent: Boolean = false,
+ @JvmField var windowingMode: Int = WindowConfiguration.WINDOWING_MODE_UNDEFINED,
+ @JvmField @Appearance var appearance: Int = 0,
+ @JvmField var scale: Float = 1f,
+ var snapshotId: Long = 0,
+) {
+ fun recycleBitmap() {
+ thumbnail?.recycle()
+ }
+
+ companion object {
+ private fun makeThumbnail(snapshot: TaskSnapshot): Bitmap {
+ var thumbnail: Bitmap? = null
+ try {
+ snapshot.hardwareBuffer?.use { buffer ->
+ thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.colorSpace)
+ }
+ } catch (ex: IllegalArgumentException) {
+ // TODO(b/157562905): Workaround for a crash when we get a snapshot without this
+ // state
+ Log.e(
+ "ThumbnailData",
+ "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE: " +
+ "${snapshot.hardwareBuffer}",
+ ex
+ )
+ }
+
+ return thumbnail
+ ?: Bitmap.createBitmap(snapshot.taskSize.x, snapshot.taskSize.y, ARGB_8888).apply {
+ eraseColor(Color.BLACK)
+ }
+ }
+
+ @JvmStatic
+ fun wrap(taskIds: IntArray?, snapshots: Array<TaskSnapshot>?): HashMap<Int, ThumbnailData> {
+ return if (taskIds == null || snapshots == null || taskIds.size != snapshots.size) {
+ HashMap()
+ } else {
+ HashMap(taskIds.associateWith { taskId -> fromSnapshot(snapshots[taskId]) })
+ }
+ }
+
+ @JvmStatic
+ fun fromSnapshot(snapshot: TaskSnapshot): ThumbnailData {
+ val thumbnail = makeThumbnail(snapshot)
+ return ThumbnailData(
+ thumbnail = thumbnail,
+ insets = Rect(snapshot.contentInsets),
+ letterboxInsets = Rect(snapshot.letterboxInsets),
+ orientation = snapshot.orientation,
+ rotation = snapshot.rotation,
+ reducedResolution = snapshot.isLowResolution,
+ // TODO(b/149579527): Pass task size instead of computing scale.
+ // Assume width and height were scaled the same; compute scale only for width
+ scale = thumbnail.width.toFloat() / snapshot.taskSize.x,
+ isRealSnapshot = snapshot.isRealSnapshot,
+ isTranslucent = snapshot.isTranslucent,
+ windowingMode = snapshot.windowingMode,
+ appearance = snapshot.appearance,
+ snapshotId = snapshot.id,
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index ca63483f656a..845ca5e8b9ec 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -147,7 +147,7 @@ public class ActivityManagerWrapper {
Log.w(TAG, "Failed to retrieve task snapshot", e);
}
if (snapshot != null) {
- return new ThumbnailData(snapshot);
+ return ThumbnailData.fromSnapshot(snapshot);
} else {
return new ThumbnailData();
}
@@ -167,7 +167,7 @@ public class ActivityManagerWrapper {
Log.w(TAG, "Failed to take task snapshot", e);
}
if (snapshot != null) {
- return new ThumbnailData(snapshot);
+ return ThumbnailData.fromSnapshot(snapshot);
} else {
return new ThumbnailData();
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index a6e04cec5f86..bbf46984208f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -42,7 +42,7 @@ public class RecentsAnimationControllerCompat {
try {
final TaskSnapshot snapshot = mAnimationController.screenshotTask(taskId);
if (snapshot != null) {
- return new ThumbnailData(snapshot);
+ return ThumbnailData.fromSnapshot(snapshot);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to screenshot task", e);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index 473719fa76df..cf8ec62f19ef 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -351,7 +351,7 @@ public class TaskStackChangeListeners {
case ON_TASK_SNAPSHOT_CHANGED: {
Trace.beginSection("onTaskSnapshotChanged");
final TaskSnapshot snapshot = (TaskSnapshot) msg.obj;
- final ThumbnailData thumbnail = new ThumbnailData(snapshot);
+ final ThumbnailData thumbnail = ThumbnailData.fromSnapshot(snapshot);
boolean snapshotConsumed = false;
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
boolean consumed = mTaskStackListeners.get(i).onTaskSnapshotChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
index 1f0459978c3c..d5e911efe570 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
@@ -37,7 +37,6 @@ import androidx.dynamicanimation.animation.SpringForce;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Flags;
import java.util.HashMap;
@@ -339,15 +338,11 @@ class MenuAnimationController {
mMenuView.updateMenuMoveToTucked(/* isMoveToTucked= */ true);
final PointF position = mMenuView.getMenuPosition();
final PointF tuckedPosition = getTuckedMenuPosition();
- if (Flags.floatingMenuAnimatedTuck()) {
- flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_X,
- Math.signum(tuckedPosition.x - position.x) * ESCAPE_VELOCITY,
- FLING_FRICTION_SCALAR,
- createDefaultSpringForce(),
- tuckedPosition.x);
- } else {
- moveToPosition(tuckedPosition);
- }
+ flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_X,
+ Math.signum(tuckedPosition.x - position.x) * ESCAPE_VELOCITY,
+ FLING_FRICTION_SCALAR,
+ createDefaultSpringForce(),
+ tuckedPosition.x);
// Keep the touch region let users could click extra space to pop up the menu view
// from the screen edge
@@ -359,23 +354,19 @@ class MenuAnimationController {
void moveOutEdgeAndShow() {
mMenuView.updateMenuMoveToTucked(/* isMoveToTucked= */ false);
- if (Flags.floatingMenuAnimatedTuck()) {
- PointF position = mMenuView.getMenuPosition();
- springMenuWith(DynamicAnimation.TRANSLATION_X,
- createDefaultSpringForce(),
- 0,
- position.x,
- true
- );
- springMenuWith(DynamicAnimation.TRANSLATION_Y,
- createDefaultSpringForce(),
- 0,
- position.y,
- true
- );
- } else {
- mMenuView.onPositionChanged();
- }
+ PointF position = mMenuView.getMenuPosition();
+ springMenuWith(DynamicAnimation.TRANSLATION_X,
+ createDefaultSpringForce(),
+ 0,
+ position.x,
+ true
+ );
+ springMenuWith(DynamicAnimation.TRANSLATION_Y,
+ createDefaultSpringForce(),
+ 0,
+ position.y,
+ true
+ );
mMenuView.onEdgeChangedIfNeeded();
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
index be75e1035ea6..9d9e7dfb7032 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -321,22 +321,6 @@ class MenuView extends FrameLayout implements
if (mMoveToTuckedListener != null) {
mMoveToTuckedListener.onMoveToTuckedChanged(isMoveToTucked);
}
-
- if (!Flags.floatingMenuAnimatedTuck()) {
- if (isMoveToTucked) {
- final float halfWidth = getMenuWidth() / 2.0f;
- final boolean isOnLeftSide = mMenuAnimationController.isOnLeftSide();
- final Rect clipBounds = new Rect(
- (int) (!isOnLeftSide ? 0 : halfWidth),
- 0,
- (int) (!isOnLeftSide ? halfWidth : getMenuWidth()),
- getMenuHeight()
- );
- setClipBounds(clipBounds);
- } else {
- setClipBounds(null);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 6dce1bb22921..0c67c5093faf 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -322,9 +322,8 @@ class MenuViewLayer extends FrameLayout implements
}
addView(mMessageView, LayerIndex.MESSAGE_VIEW);
- if (Flags.floatingMenuAnimatedTuck()) {
- setClipChildren(true);
- }
+ setClipChildren(true);
+
setClickable(false);
setFocusable(false);
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
@@ -476,10 +475,8 @@ class MenuViewLayer extends FrameLayout implements
mMenuAnimationController.startTuckedAnimationPreview();
}
- if (Flags.floatingMenuAnimatedTuck()) {
- if (!mMenuView.isMoveToTucked()) {
- setClipBounds(null);
- }
+ if (!mMenuView.isMoveToTucked()) {
+ setClipBounds(null);
}
mMenuView.onArrivalAtPosition(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt
index cc524840947b..ca03a00cca0c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt
@@ -34,6 +34,7 @@ import android.hardware.biometrics.events.AuthenticationStoppedInfo
import android.hardware.biometrics.events.AuthenticationSucceededInfo
import android.hardware.face.FaceManager
import android.hardware.fingerprint.FingerprintManager
+import android.util.Log
import com.android.systemui.biometrics.shared.model.AuthenticationReason
import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
import com.android.systemui.biometrics.shared.model.AuthenticationState
@@ -52,6 +53,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.shareIn
/** A repository for the state of biometric authentication. */
@@ -85,6 +87,7 @@ constructor(
private val authenticationState: Flow<AuthenticationState> =
conflatedCallbackFlow {
val updateAuthenticationState = { state: AuthenticationState ->
+ Log.d(TAG, "authenticationState updated: $state")
trySendWithFailureLogging(state, TAG, "Error sending AuthenticationState state")
}
@@ -187,6 +190,7 @@ constructor(
it.biometricSourceType == BiometricSourceType.FINGERPRINT)
}
.map { it.requestReason }
+ .onEach { Log.d(TAG, "fingerprintAuthenticationReason updated: $it") }
override val fingerprintAcquiredStatus: Flow<FingerprintAuthenticationStatus> =
authenticationState
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
index 40d38dd83154..6b61adce3c84 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
@@ -30,10 +30,10 @@ import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.biometrics.shared.model.toSensorStrength
import com.android.systemui.biometrics.shared.model.toSensorType
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -42,6 +42,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
@@ -52,7 +53,7 @@ import kotlinx.coroutines.withContext
*/
interface FingerprintPropertyRepository {
/** Whether the fingerprint properties have been initialized yet. */
- val propertiesInitialized: StateFlow<Boolean>
+ val propertiesInitialized: Flow<Boolean>
/** The id of fingerprint sensor. */
val sensorId: Flow<Int>
@@ -110,14 +111,8 @@ constructor(
initialValue = UNINITIALIZED_PROPS,
)
- override val propertiesInitialized: StateFlow<Boolean> =
- props
- .map { it != UNINITIALIZED_PROPS }
- .stateIn(
- applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = props.value != UNINITIALIZED_PROPS,
- )
+ override val propertiesInitialized: Flow<Boolean> =
+ props.map { it != UNINITIALIZED_PROPS }.onStart { emit(props.value != UNINITIALIZED_PROPS) }
override val sensorId: Flow<Int> = props.map { it.sensorId }
@@ -141,7 +136,7 @@ constructor(
companion object {
private const val TAG = "FingerprintPropertyRepositoryImpl"
- private val UNINITIALIZED_PROPS =
+ val UNINITIALIZED_PROPS =
FingerprintSensorPropertiesInternal(
-2 /* sensorId */,
SensorProperties.STRENGTH_CONVENIENCE,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt
index 6e79e4693728..83aefcaac36d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.domain.interactor
import android.app.ActivityTaskManager
+import android.util.Log
import com.android.systemui.biometrics.data.repository.BiometricStatusRepository
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.biometrics.shared.model.AuthenticationReason
@@ -26,6 +27,7 @@ import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.onEach
/** Encapsulates business logic for interacting with biometric authentication state. */
interface BiometricStatusInteractor {
@@ -49,15 +51,20 @@ constructor(
override val sfpsAuthenticationReason: Flow<AuthenticationReason> =
combine(
- biometricStatusRepository.fingerprintAuthenticationReason,
- fingerprintPropertyRepository.sensorType
- ) { reason: AuthenticationReason, sensorType ->
- if (sensorType.isPowerButton() && reason.isReasonToAlwaysUpdateSfpsOverlay(activityTaskManager)) {
- reason
- } else {
- AuthenticationReason.NotRunning
+ biometricStatusRepository.fingerprintAuthenticationReason,
+ fingerprintPropertyRepository.sensorType
+ ) { reason: AuthenticationReason, sensorType ->
+ if (
+ sensorType.isPowerButton() &&
+ reason.isReasonToAlwaysUpdateSfpsOverlay(activityTaskManager)
+ ) {
+ reason
+ } else {
+ AuthenticationReason.NotRunning
+ }
}
- }.distinctUntilChanged()
+ .distinctUntilChanged()
+ .onEach { Log.d(TAG, "sfpsAuthenticationReason updated: $it") }
override val fingerprintAcquiredStatus: Flow<FingerprintAuthenticationStatus> =
biometricStatusRepository.fingerprintAcquiredStatus
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
index 3112b673d724..d5b450d1e2a8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
@@ -46,7 +46,7 @@ constructor(
displayStateInteractor: DisplayStateInteractor,
udfpsOverlayInteractor: UdfpsOverlayInteractor,
) {
- val propertiesInitialized: StateFlow<Boolean> = repository.propertiesInitialized
+ val propertiesInitialized: Flow<Boolean> = repository.propertiesInitialized
val isUdfps: StateFlow<Boolean> =
repository.sensorType
.map { it.isUdfps() }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index f0969eda4029..13ea3f56d911 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -199,29 +199,32 @@ object BiometricViewSizeBinder {
iconParams.leftMargin = position.left
mediumConstraintSet.clear(
R.id.biometric_icon,
- ConstraintSet.END
+ ConstraintSet.RIGHT
)
mediumConstraintSet.connect(
R.id.biometric_icon,
- ConstraintSet.START,
+ ConstraintSet.LEFT,
ConstraintSet.PARENT_ID,
- ConstraintSet.START
+ ConstraintSet.LEFT
)
mediumConstraintSet.setMargin(
R.id.biometric_icon,
- ConstraintSet.START,
+ ConstraintSet.LEFT,
position.left
)
- smallConstraintSet.clear(R.id.biometric_icon, ConstraintSet.END)
+ smallConstraintSet.clear(
+ R.id.biometric_icon,
+ ConstraintSet.RIGHT
+ )
smallConstraintSet.connect(
R.id.biometric_icon,
- ConstraintSet.START,
+ ConstraintSet.LEFT,
ConstraintSet.PARENT_ID,
- ConstraintSet.START
+ ConstraintSet.LEFT
)
smallConstraintSet.setMargin(
R.id.biometric_icon,
- ConstraintSet.START,
+ ConstraintSet.LEFT,
position.left
)
}
@@ -252,32 +255,32 @@ object BiometricViewSizeBinder {
iconParams.rightMargin = position.right
mediumConstraintSet.clear(
R.id.biometric_icon,
- ConstraintSet.START
+ ConstraintSet.LEFT
)
mediumConstraintSet.connect(
R.id.biometric_icon,
- ConstraintSet.END,
+ ConstraintSet.RIGHT,
ConstraintSet.PARENT_ID,
- ConstraintSet.END
+ ConstraintSet.RIGHT
)
mediumConstraintSet.setMargin(
R.id.biometric_icon,
- ConstraintSet.END,
+ ConstraintSet.RIGHT,
position.right
)
smallConstraintSet.clear(
R.id.biometric_icon,
- ConstraintSet.START
+ ConstraintSet.LEFT
)
smallConstraintSet.connect(
R.id.biometric_icon,
- ConstraintSet.END,
+ ConstraintSet.RIGHT,
ConstraintSet.PARENT_ID,
- ConstraintSet.END
+ ConstraintSet.RIGHT
)
smallConstraintSet.setMargin(
R.id.biometric_icon,
- ConstraintSet.END,
+ ConstraintSet.RIGHT,
position.right
)
}
@@ -383,15 +386,15 @@ object BiometricViewSizeBinder {
// Move all content to other panel
flipConstraintSet.connect(
R.id.scrollView,
- ConstraintSet.START,
+ ConstraintSet.LEFT,
R.id.midGuideline,
- ConstraintSet.START
+ ConstraintSet.LEFT
)
flipConstraintSet.connect(
R.id.scrollView,
- ConstraintSet.END,
+ ConstraintSet.RIGHT,
R.id.rightGuideline,
- ConstraintSet.END
+ ConstraintSet.RIGHT
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
index 4bdbfa272ecc..ff7ac35ba56b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
@@ -20,6 +20,7 @@ package com.android.systemui.biometrics.ui.binder
import android.content.Context
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
+import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
@@ -91,6 +92,13 @@ constructor(
showIndicatorForDeviceEntry,
progressBarIsVisible) =
combinedFlows
+ Log.d(
+ TAG,
+ "systemServerAuthReason = $systemServerAuthReason, " +
+ "showIndicatorForDeviceEntry = " +
+ "$showIndicatorForDeviceEntry, " +
+ "progressBarIsVisible = $progressBarIsVisible"
+ )
if (!isInRearDisplayMode) {
if (progressBarIsVisible) {
hide()
@@ -114,6 +122,10 @@ constructor(
/** Show the side fingerprint sensor indicator */
private fun show() {
if (overlayView?.isAttachedToWindow == true) {
+ Log.d(
+ TAG,
+ "show(): overlayView $overlayView isAttachedToWindow already, ignoring show request"
+ )
return
}
@@ -128,6 +140,7 @@ constructor(
)
bind(overlayView!!, overlayViewModel, fpsUnlockTracker.get(), windowManager.get())
overlayView!!.visibility = View.INVISIBLE
+ Log.d(TAG, "show(): adding overlayView $overlayView")
windowManager.get().addView(overlayView, overlayViewModel.defaultOverlayViewParams)
}
@@ -137,6 +150,7 @@ constructor(
val lottie = overlayView!!.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
lottie.pauseAnimation()
lottie.removeAllLottieOnCompositionLoadedListener()
+ Log.d(TAG, "hide(): removing overlayView $overlayView, setting to null")
windowManager.get().removeView(overlayView)
overlayView = null
}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
index f0230beaa967..911145b62661 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
@@ -419,8 +419,7 @@ internal constructor(
const val ACTION_PREVIOUSLY_CONNECTED_DEVICE =
"com.android.settings.PREVIOUSLY_CONNECTED_DEVICE"
const val ACTION_PAIR_NEW_DEVICE = "android.settings.BLUETOOTH_PAIRING_SETTINGS"
- const val ACTION_AUDIO_SHARING =
- "com.google.android.settings.BLUETOOTH_AUDIO_SHARING_SETTINGS"
+ const val ACTION_AUDIO_SHARING = "com.android.settings.BLUETOOTH_AUDIO_SHARING_SETTINGS"
const val DISABLED_ALPHA = 0.3f
const val ENABLED_ALPHA = 1f
const val PROGRESS_BAR_ANIMATION_DURATION_MS = 1500L
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepository.kt b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepository.kt
index c018ecb25835..0544a4f66295 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepository.kt
@@ -18,6 +18,8 @@ package com.android.systemui.brightness.data.repository
import android.content.Context
import android.os.UserManager
+import com.android.settingslib.RestrictedLockUtils
+import com.android.systemui.Flags.enforceBrightnessBaseUserRestriction
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -66,7 +68,18 @@ constructor(
user.id
)
?.let { PolicyRestriction.Restricted(it) }
- ?: PolicyRestriction.NoRestriction
+ ?: if (
+ enforceBrightnessBaseUserRestriction() &&
+ userRestrictionChecker.hasBaseUserRestriction(
+ applicationContext,
+ UserManager.DISALLOW_CONFIG_BRIGHTNESS,
+ user.id
+ )
+ ) {
+ PolicyRestriction.Restricted(RestrictedLockUtils.EnforcedAdmin())
+ } else {
+ PolicyRestriction.NoRestriction
+ }
}
.flowOn(backgroundDispatcher)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 06c83962df6b..9599a8864bcc 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -61,7 +61,6 @@ import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.UserTracker
import com.android.systemui.smartspace.data.repository.SmartspaceRepository
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
-import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import com.android.systemui.util.kotlin.emitOnStart
import javax.inject.Inject
@@ -130,7 +129,7 @@ constructor(
allOf(
communalSettingsInteractor.isCommunalEnabled,
not(keyguardInteractor.isEncryptedOrLockdown),
- anyOf(keyguardInteractor.isKeyguardShowing, keyguardInteractor.isDreaming)
+ keyguardInteractor.isKeyguardShowing
)
.distinctUntilChanged()
.onEach { available ->
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index f6122ad48300..c0dc313e14f7 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -96,6 +96,8 @@ constructor(
uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_CANCEL)
}
+ val isIdleOnCommunal: StateFlow<Boolean> = communalInteractor.isIdleOnCommunal
+
/** Launch the widget picker activity using the given {@link ActivityResultLauncher}. */
suspend fun onOpenWidgetPicker(
resources: Resources,
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 656e5cbafa97..97db43bdf0f8 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -25,6 +25,7 @@ import com.android.systemui.communal.domain.model.CommunalContentModel
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.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.log.LogBuffer
@@ -63,6 +64,7 @@ constructor(
@Application private val scope: CoroutineScope,
@Main private val resources: Resources,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ keyguardInteractor: KeyguardInteractor,
private val communalInteractor: CommunalInteractor,
tutorialInteractor: CommunalTutorialInteractor,
private val shadeInteractor: ShadeInteractor,
@@ -236,6 +238,14 @@ constructor(
*/
val touchesAllowed: Flow<Boolean> = not(shadeInteractor.isAnyFullyExpanded)
+ // TODO(b/339667383): remove this temporary swipe gesture handle
+ /**
+ * The dream overlay has its own gesture handle as the SysUI window is not visible above the
+ * dream. This flow will be false when dreaming so that we don't show a duplicate handle when
+ * opening the hub over the dream.
+ */
+ val showGestureIndicator: Flow<Boolean> = not(keyguardInteractor.isDreaming)
+
companion object {
const val POPUP_AUTO_HIDE_TIMEOUT_MS = 12000L
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index f20fafccfd19..426f484e4d02 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -44,6 +44,7 @@ import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
import javax.inject.Inject
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
/** An Activity for editing the widgets that appear in hub mode. */
@@ -69,6 +70,8 @@ constructor(
private var shouldOpenWidgetPickerOnStart = false
+ private var lockOnDestroy = false
+
private val addWidgetActivityLauncher: ActivityResultLauncher<Intent> =
registerForActivityResult(StartActivityForResult()) { result ->
when (result.resultCode) {
@@ -149,15 +152,18 @@ constructor(
}
private fun onEditDone() {
- try {
+ lifecycleScope.launch {
communalViewModel.changeScene(
CommunalScenes.Communal,
CommunalTransitionKeys.SimpleFade
)
- checkNotNull(windowManagerService).lockNow(/* options */ null)
+
+ // Wait for the current scene to be idle on communal.
+ communalViewModel.isIdleOnCommunal.first { it }
+ // Then finish the activity (this helps to avoid a flash of lockscreen when locking
+ // in onDestroy()).
+ lockOnDestroy = true
finish()
- } catch (e: RemoteException) {
- Log.e(TAG, "Couldn't lock the device as WindowManager is dead.")
}
}
@@ -190,5 +196,15 @@ constructor(
override fun onDestroy() {
super.onDestroy()
communalViewModel.setEditModeOpen(false)
+
+ if (lockOnDestroy) lockNow()
+ }
+
+ private fun lockNow() {
+ try {
+ checkNotNull(windowManagerService).lockNow(/* options */ null)
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Couldn't lock the device as WindowManager is dead.")
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt
deleted file mode 100644
index 0daa058720ba..000000000000
--- a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.contrast
-
-import android.app.UiModeManager
-import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_HIGH
-import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_MEDIUM
-import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_STANDARD
-import android.app.UiModeManager.ContrastUtils.fromContrastLevel
-import android.app.UiModeManager.ContrastUtils.toContrastLevel
-import android.os.Bundle
-import android.provider.Settings
-import android.view.View
-import android.widget.FrameLayout
-import com.android.internal.annotations.VisibleForTesting
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.res.R
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.util.settings.SecureSettings
-import java.util.concurrent.Executor
-import javax.inject.Inject
-
-/** Dialog to select contrast options */
-class ContrastDialogDelegate
-@Inject
-constructor(
- private val sysuiDialogFactory: SystemUIDialog.Factory,
- @Main private val mainExecutor: Executor,
- private val uiModeManager: UiModeManager,
- private val userTracker: UserTracker,
- private val secureSettings: SecureSettings,
-) : SystemUIDialog.Delegate, UiModeManager.ContrastChangeListener {
-
- @VisibleForTesting lateinit var contrastButtons: Map<Int, FrameLayout>
- lateinit var dialogView: View
- @VisibleForTesting var initialContrast: Float = fromContrastLevel(CONTRAST_LEVEL_STANDARD)
-
- override fun createDialog(): SystemUIDialog {
- val dialog = sysuiDialogFactory.create(this)
- dialogView = dialog.layoutInflater.inflate(R.layout.contrast_dialog, null)
- with(dialog) {
- setView(dialogView)
-
- setTitle(R.string.quick_settings_contrast_label)
- setNeutralButton(R.string.cancel) { _, _ ->
- secureSettings.putFloatForUser(
- Settings.Secure.CONTRAST_LEVEL,
- initialContrast,
- userTracker.userId
- )
- dialog.dismiss()
- }
- setPositiveButton(com.android.settingslib.R.string.done) { _, _ -> dialog.dismiss() }
- }
-
- return dialog
- }
-
- override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
- contrastButtons =
- mapOf(
- CONTRAST_LEVEL_STANDARD to dialog.requireViewById(R.id.contrast_button_standard),
- CONTRAST_LEVEL_MEDIUM to dialog.requireViewById(R.id.contrast_button_medium),
- CONTRAST_LEVEL_HIGH to dialog.requireViewById(R.id.contrast_button_high)
- )
-
- contrastButtons.forEach { (contrastLevel, contrastButton) ->
- contrastButton.setOnClickListener {
- val contrastValue = fromContrastLevel(contrastLevel)
- secureSettings.putFloatForUser(
- Settings.Secure.CONTRAST_LEVEL,
- contrastValue,
- userTracker.userId
- )
- }
- }
-
- initialContrast = uiModeManager.contrast
- highlightContrast(toContrastLevel(initialContrast))
- }
-
- override fun onStart(dialog: SystemUIDialog) {
- uiModeManager.addContrastChangeListener(mainExecutor, this)
- }
-
- override fun onStop(dialog: SystemUIDialog) {
- uiModeManager.removeContrastChangeListener(this)
- }
-
- override fun onContrastChanged(contrast: Float) {
- highlightContrast(toContrastLevel(contrast))
- }
-
- private fun highlightContrast(contrast: Int) {
- contrastButtons.forEach { (level, button) -> button.isSelected = level == contrast }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index d2df276002cc..c2e1e33f5318 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -20,7 +20,6 @@ import android.app.Activity;
import com.android.systemui.ForegroundServicesDialog;
import com.android.systemui.communal.widgets.EditWidgetsActivity;
-import com.android.systemui.contrast.ContrastDialogActivity;
import com.android.systemui.keyguard.WorkLockActivity;
import com.android.systemui.people.PeopleSpaceActivity;
import com.android.systemui.people.widget.LaunchConversationActivity;
@@ -72,12 +71,6 @@ public abstract class DefaultActivityBinder {
@ClassKey(BrightnessDialog.class)
public abstract Activity bindBrightnessDialog(BrightnessDialog activity);
- /** Inject into ContrastDialogActivity. */
- @Binds
- @IntoMap
- @ClassKey(ContrastDialogActivity.class)
- public abstract Activity bindContrastDialogActivity(ContrastDialogActivity activity);
-
/** Inject into UsbDebuggingActivity. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 60006c68639d..1e725eb71dde 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -21,6 +21,8 @@ import static android.service.dreams.Flags.dreamHandlesBeingObscured;
import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress;
import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamAlphaScaledExpansion;
import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamYPositionScaledExpansion;
+import static com.android.systemui.Flags.communalHub;
+import static com.android.systemui.Flags.glanceableHubGestureHandle;
import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_BOTTOM;
import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_TOP;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
@@ -185,6 +187,7 @@ public class DreamOverlayContainerViewController extends
DreamOverlayContainerView containerView,
ComplicationHostViewController complicationHostViewController,
@Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
+ @Named(DreamOverlayModule.HUB_GESTURE_INDICATOR_VIEW) View hubGestureIndicatorView,
DreamOverlayStatusBarViewController statusBarViewController,
LowLightTransitionCoordinator lowLightTransitionCoordinator,
BlurUtils blurUtils,
@@ -220,6 +223,12 @@ public class DreamOverlayContainerViewController extends
mComplicationHostViewController = complicationHostViewController;
mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize(
R.dimen.dream_overlay_y_offset);
+
+ if (communalHub() && glanceableHubGestureHandle()) {
+ // TODO(b/339667383): remove this temporary swipe gesture handle
+ hubGestureIndicatorView.setVisibility(View.VISIBLE);
+ }
+
final View view = mComplicationHostViewController.getView();
mDreamOverlayContentView.addView(view,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index 999e6813ea55..789b7f8550d7 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -18,6 +18,7 @@ package com.android.systemui.dreams.dagger;
import android.content.res.Resources;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
import androidx.lifecycle.Lifecycle;
@@ -39,6 +40,7 @@ import javax.inject.Named;
@Module
public abstract class DreamOverlayModule {
public static final String DREAM_OVERLAY_CONTENT_VIEW = "dream_overlay_content_view";
+ public static final String HUB_GESTURE_INDICATOR_VIEW = "hub_gesture_indicator_view";
public static final String MAX_BURN_IN_OFFSET = "max_burn_in_offset";
public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL =
"burn_in_protection_update_interval";
@@ -71,6 +73,18 @@ public abstract class DreamOverlayModule {
"R.id.dream_overlay_content must not be null");
}
+ /**
+ * Gesture indicator bar on the right edge of the screen to indicate to users that they can
+ * swipe to see their widgets on lock screen.
+ */
+ @Provides
+ @DreamOverlayComponent.DreamOverlayScope
+ @Named(HUB_GESTURE_INDICATOR_VIEW)
+ public static View providesHubGestureIndicatorView(DreamOverlayContainerView view) {
+ return Preconditions.checkNotNull(view.findViewById(R.id.glanceable_hub_handle),
+ "R.id.glanceable_hub_handle must not be null");
+ }
+
/** */
@Provides
public static TouchInsetManager.TouchInsetSession providesTouchInsetSession(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 7655d7a89dc3..f488d3b67fc7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -34,6 +34,7 @@ import java.util.UUID
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -42,6 +43,7 @@ import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.sync.Mutex
/**
* The source of truth for all keyguard transitions.
@@ -129,6 +131,7 @@ constructor(
private var lastStep: TransitionStep = TransitionStep()
private var lastAnimator: ValueAnimator? = null
+ private val _currentTransitionMutex = Mutex()
private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> =
MutableStateFlow(
TransitionInfo(
@@ -146,6 +149,9 @@ constructor(
*/
private var updateTransitionId: UUID? = null
+ // Only used in a test environment
+ var forceDelayForRaceConditionTest = false
+
init {
// Start with a FINISHED transition in OFF. KeyguardBootInteractor will transition from OFF
// to either GONE or LOCKSCREEN once we're booted up and can determine which state we should
@@ -162,9 +168,21 @@ constructor(
override suspend fun startTransition(info: TransitionInfo): UUID? {
_currentTransitionInfo.value = info
+ Log.d(TAG, "(Internal) Setting current transition info: $info")
+
+ // There is no fairness guarantee with 'withContext', which means that transitions could
+ // be processed out of order. Use a Mutex to guarantee ordering.
+ _currentTransitionMutex.lock()
+
+ // Only used in a test environment
+ if (forceDelayForRaceConditionTest) {
+ delay(50L)
+ }
// Animators must be started on the main thread.
return withContext("$TAG#startTransition", mainDispatcher) {
+ _currentTransitionMutex.unlock()
+
if (lastStep.from == info.from && lastStep.to == info.to) {
Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
return@withContext null
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
index eef4b97ae34d..96260770d89f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.content.Context
+import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
@@ -39,6 +40,7 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
/**
@@ -96,10 +98,13 @@ constructor(
keyguardUpdateMonitor.isFingerprintDetectionRunning &&
keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed
}
+ .onEach { Log.d(TAG, "showIndicatorForPrimaryBouncer updated: $it") }
private val showIndicatorForAlternateBouncer: Flow<Boolean> =
// Note: this interactor internally verifies that SideFPS is enabled and running.
- alternateBouncerInteractor.isVisible
+ alternateBouncerInteractor.isVisible.onEach {
+ Log.d(TAG, "showIndicatorForAlternateBouncer updated: $it")
+ }
/**
* Indicates whether the primary or alternate bouncers request showing the side fingerprint
@@ -112,6 +117,7 @@ constructor(
showForPrimaryBouncer || showForAlternateBouncer
}
.distinctUntilChanged()
+ .onEach { Log.d(TAG, "showIndicatorForDeviceEntry updated: $it") }
private fun isBouncerActive(): Boolean {
if (SceneContainerFlag.isEnabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
index 857096e1c03b..b1ef76eba481 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
@@ -20,6 +20,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.content.Context
+import android.util.Log
import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.dagger.SysUISingleton
@@ -42,6 +43,7 @@ import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@SysUISingleton
@@ -78,7 +80,15 @@ constructor(
private val refreshEvents: Flow<Unit> =
merge(
configurationInteractor.onAnyConfigurationChange,
- fingerprintPropertyInteractor.propertiesInitialized.filter { it }.map { Unit },
+ fingerprintPropertyInteractor.propertiesInitialized
+ .filter { it }
+ .map { Unit }
+ .onEach {
+ Log.d(
+ "KeyguardBlueprintInteractor",
+ "triggering refreshEvent from fpPropertiesInitialized"
+ )
+ },
)
init {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index 75c4d6f6fea6..cf6942e2f245 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -56,12 +56,6 @@ constructor(
}
scope.launch {
- sharedNotificationContainerViewModel
- .getMaxNotifications { height, useExtraShelfSpace -> height.toInt() }
- .collect { logger.log(TAG, VERBOSE, "Notif: max height in px", it) }
- }
-
- scope.launch {
sharedNotificationContainerViewModel.isOnLockscreen.collect {
logger.log(TAG, VERBOSE, "Notif: isOnLockscreen", it)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
index b2a24ca85b07..323ceef06a97 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
@@ -229,6 +229,7 @@ sealed class TransitionInteractor(
startTransitionTo(
toState = KeyguardState.OCCLUDED,
modeOnCanceled = TransitionModeOnCanceled.RESET,
+ ownerReason = "keyguardInteractor.onCameraLaunchDetected",
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index 229e592a6a0c..19e3e0715989 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -308,7 +308,11 @@ constructor(
* It will be called when the container is out of view.
*/
lateinit var updateUserVisibility: () -> Unit
- lateinit var updateHostVisibility: () -> Unit
+ var updateHostVisibility: () -> Unit = {}
+ set(value) {
+ field = value
+ mediaCarouselViewModel.updateHostVisibility = value
+ }
private val isReorderingAllowed: Boolean
get() = visualStabilityProvider.isReorderingAllowed
@@ -345,6 +349,20 @@ constructor(
configurationController.addCallback(configListener)
if (!mediaFlags.isMediaControlsRefactorEnabled()) {
setUpListeners()
+ } else {
+ val visualStabilityCallback = OnReorderingAllowedListener {
+ mediaCarouselViewModel.onReorderingAllowed()
+
+ // Update user visibility so that no extra impression will be logged when
+ // activeMediaIndex resets to 0
+ if (this::updateUserVisibility.isInitialized) {
+ updateUserVisibility()
+ }
+
+ // Let's reset our scroll position
+ mediaCarouselScrollHandler.scrollToStart()
+ }
+ visualStabilityProvider.addPersistentReorderingAllowedListener(visualStabilityCallback)
}
mediaFrame.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
// The pageIndicator is not laid out yet when we get the current state update,
@@ -366,10 +384,6 @@ constructor(
)
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
mediaCarousel.repeatWhenAttached {
- if (mediaFlags.isMediaControlsRefactorEnabled()) {
- mediaCarouselViewModel.onAttached()
- mediaCarouselScrollHandler.scrollToStart()
- }
repeatOnLifecycle(Lifecycle.State.STARTED) {
listenForAnyStateToGoneKeyguardTransition(this)
listenForAnyStateToLockscreenTransition(this)
@@ -592,9 +606,7 @@ constructor(
if (!immediately) {
// Although it wasn't requested, we were able to process the removal
// immediately since reordering is allowed. So, notify hosts to update
- if (this@MediaCarouselController::updateHostVisibility.isInitialized) {
- updateHostVisibility()
- }
+ updateHostVisibility()
}
} else {
keysNeedRemoval.add(key)
@@ -751,6 +763,7 @@ constructor(
}
}
viewController.setListening(mediaCarouselScrollHandler.visibleToUser && currentlyExpanded)
+ controllerByViewModel[commonViewModel] = viewController
updateViewControllerToState(viewController, noAnimation = true)
updatePageIndicator()
if (
@@ -764,7 +777,6 @@ constructor(
mediaCarouselScrollHandler.onPlayersChanged()
mediaFrame.requiresRemeasuring = true
commonViewModel.onAdded(commonViewModel)
- controllerByViewModel[commonViewModel] = viewController
}
private fun onUpdated(commonViewModel: MediaCommonViewModel) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
index fd5f44594ae8..4e9093642c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
@@ -57,12 +57,12 @@ constructor(
val mediaItems: StateFlow<List<MediaCommonViewModel>> =
interactor.currentMedia
.map { sortedItems ->
- buildList {
+ val mediaList = buildList {
sortedItems.forEach { commonModel ->
// When view is started we should make sure to clean models that are pending
// removal.
// This action should only be triggered once.
- if (!isAttached || !modelsPendingRemoval.contains(commonModel)) {
+ if (!allowReorder || !modelsPendingRemoval.contains(commonModel)) {
when (commonModel) {
is MediaCommonModel.MediaControl -> add(toViewModel(commonModel))
is MediaCommonModel.MediaRecommendations ->
@@ -70,11 +70,16 @@ constructor(
}
}
}
- if (isAttached) {
- modelsPendingRemoval.clear()
+ }
+ if (allowReorder) {
+ if (modelsPendingRemoval.size > 0) {
+ updateHostVisibility()
}
- isAttached = false
+ modelsPendingRemoval.clear()
}
+ allowReorder = false
+
+ mediaList
}
.stateIn(
scope = applicationScope,
@@ -82,6 +87,8 @@ constructor(
initialValue = emptyList(),
)
+ var updateHostVisibility: () -> Unit = {}
+
private val mediaControlByInstanceId =
mutableMapOf<InstanceId, MediaCommonViewModel.MediaControl>()
@@ -89,15 +96,15 @@ constructor(
private var modelsPendingRemoval: MutableSet<MediaCommonModel> = mutableSetOf()
- private var isAttached = false
+ private var allowReorder = false
fun onSwipeToDismiss() {
logger.logSwipeDismiss()
interactor.onSwipeToDismiss()
}
- fun onAttached() {
- isAttached = true
+ fun onReorderingAllowed() {
+ allowReorder = true
interactor.reorderMedia()
}
@@ -194,7 +201,11 @@ constructor(
) {
if (immediatelyRemove || isReorderingAllowed()) {
interactor.dismissSmartspaceRecommendation(commonModel.recsLoadingModel.key, 0L)
- // TODO if not immediate remove update host visibility
+ if (!immediatelyRemove) {
+ // Although it wasn't requested, we were able to process the removal
+ // immediately since reordering is allowed. So, notify hosts to update
+ updateHostVisibility()
+ }
} else {
modelsPendingRemoval.add(commonModel)
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt
index 412c006806bf..9265bfb2f66b 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt
@@ -140,10 +140,11 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
val bitmapShader = bitmapShader ?: return
val thumbnailData = thumbnailData ?: return
+ val thumbnail = thumbnailData.thumbnail ?: return
val display = context.display ?: return
val windowMetrics = windowManager.maximumWindowMetrics
- previewRect.set(0, 0, thumbnailData.thumbnail.width, thumbnailData.thumbnail.height)
+ previewRect.set(0, 0, thumbnail.width, thumbnail.height)
val currentRotation: Int = display.rotation
val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL
diff --git a/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt b/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt
index 3907a7240258..5e6ee4d3c700 100644
--- a/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt
@@ -16,12 +16,20 @@
package com.android.systemui.qrcodescanner.dagger
+import com.android.systemui.Flags
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.qs.tiles.QRCodeScannerTile
+import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory
+import com.android.systemui.qs.tiles.impl.qr.domain.interactor.QRCodeScannerTileDataInteractor
+import com.android.systemui.qs.tiles.impl.qr.domain.interactor.QRCodeScannerTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.qr.domain.model.QRCodeScannerTileModel
+import com.android.systemui.qs.tiles.impl.qr.ui.QRCodeScannerTileMapper
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
+import com.android.systemui.qs.tiles.viewmodel.StubQSTileViewModel
import com.android.systemui.res.R
import dagger.Binds
import dagger.Module
@@ -54,5 +62,24 @@ interface QRCodeScannerModule {
),
instanceId = uiEventLogger.getNewInstanceId(),
)
+
+ /** Inject QR Code Scanner Tile into tileViewModelMap in QSModule. */
+ @Provides
+ @IntoMap
+ @StringKey(QR_CODE_SCANNER_TILE_SPEC)
+ fun provideQRCodeScannerTileViewModel(
+ factory: QSTileViewModelFactory.Static<QRCodeScannerTileModel>,
+ mapper: QRCodeScannerTileMapper,
+ stateInteractor: QRCodeScannerTileDataInteractor,
+ userActionInteractor: QRCodeScannerTileUserActionInteractor
+ ): QSTileViewModel =
+ if (Flags.qsNewTilesFuture())
+ factory.create(
+ TileSpec.create(QR_CODE_SCANNER_TILE_SPEC),
+ userActionInteractor,
+ stateInteractor,
+ mapper,
+ )
+ else StubQSTileViewModel
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileStateToProto.kt b/packages/SystemUI/src/com/android/systemui/qs/TileStateToProto.kt
index 2c8a5a4981d0..1336d640a9e5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileStateToProto.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileStateToProto.kt
@@ -18,6 +18,7 @@ package com.android.systemui.qs
import android.service.quicksettings.Tile
import android.text.TextUtils
+import android.widget.Switch
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.external.CustomTile
import com.android.systemui.qs.nano.QsTileState
@@ -44,8 +45,8 @@ fun QSTile.State.toProto(): QsTileState? {
}
label?.let { state.label = it.toString() }
secondaryLabel?.let { state.secondaryLabel = it.toString() }
- if (this is QSTile.BooleanState) {
- state.booleanState = value
+ if (expandedAccessibilityClassName == Switch::class.java.name) {
+ state.booleanState = state.state == QsTileState.ACTIVE
}
return state
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index d26ae0a4dac8..5d35a69be910 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -42,6 +42,7 @@ import android.text.format.DateUtils;
import android.util.Log;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
+import android.widget.Button;
import android.widget.Switch;
import androidx.annotation.Nullable;
@@ -502,6 +503,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener,
if (state instanceof BooleanState) {
state.expandedAccessibilityClassName = Switch.class.getName();
((BooleanState) state).value = (state.state == Tile.STATE_ACTIVE);
+ } else {
+ state.expandedAccessibilityClassName = Button.class.getName();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 206879905782..71b69c92b87d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import static com.android.settingslib.satellite.SatelliteDialogUtils.TYPE_IS_AIRPLANE_MODE;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -32,9 +34,12 @@ import android.telephony.TelephonyManager;
import android.widget.Switch;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.telephony.flags.Flags;
+import com.android.settingslib.satellite.SatelliteDialogUtils;
import com.android.systemui.animation.Expandable;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Background;
@@ -54,6 +59,8 @@ import com.android.systemui.util.settings.GlobalSettings;
import dagger.Lazy;
+import kotlinx.coroutines.Job;
+
import javax.inject.Inject;
/** Quick settings tile: Airplane mode **/
@@ -66,6 +73,9 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> {
private final Lazy<ConnectivityManager> mLazyConnectivityManager;
private boolean mListening;
+ @Nullable
+ @VisibleForTesting
+ Job mClickJob;
@Inject
public AirplaneModeTile(
@@ -111,6 +121,21 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> {
new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS), 0);
return;
}
+
+ if (Flags.oemEnabledSatelliteFlag()) {
+ if (mClickJob != null && !mClickJob.isCompleted()) {
+ return;
+ }
+ mClickJob = SatelliteDialogUtils.mayStartSatelliteWarningDialog(
+ mContext, this, TYPE_IS_AIRPLANE_MODE, isAllowClick -> {
+ if (isAllowClick) {
+ setEnabled(!airplaneModeEnabled);
+ }
+ return null;
+ });
+ return;
+ }
+
setEnabled(!airplaneModeEnabled);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 9af34f6c9918..9f41d98b6969 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles;
+import static com.android.settingslib.satellite.SatelliteDialogUtils.TYPE_IS_BLUETOOTH;
import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
import android.annotation.Nullable;
@@ -33,11 +34,14 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.Switch;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.satellite.SatelliteDialogUtils;
import com.android.systemui.animation.Expandable;
import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogViewModel;
import com.android.systemui.dagger.qualifiers.Background;
@@ -55,6 +59,8 @@ import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.BluetoothController;
+import kotlinx.coroutines.Job;
+
import java.util.List;
import java.util.concurrent.Executor;
@@ -78,6 +84,9 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
private final BluetoothTileDialogViewModel mDialogViewModel;
private final FeatureFlags mFeatureFlags;
+ @Nullable
+ @VisibleForTesting
+ Job mClickJob;
@Inject
public BluetoothTile(
@@ -110,6 +119,24 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
@Override
protected void handleClick(@Nullable Expandable expandable) {
+ if (com.android.internal.telephony.flags.Flags.oemEnabledSatelliteFlag()) {
+ if (mClickJob != null && !mClickJob.isCompleted()) {
+ return;
+ }
+ mClickJob = SatelliteDialogUtils.mayStartSatelliteWarningDialog(
+ mContext, this, TYPE_IS_BLUETOOTH, isAllowClick -> {
+ if (!isAllowClick) {
+ return null;
+ }
+ handleClickEvent(expandable);
+ return null;
+ });
+ return;
+ }
+ handleClickEvent(expandable);
+ }
+
+ private void handleClickEvent(@Nullable Expandable expandable) {
if (mFeatureFlags.isEnabled(Flags.BLUETOOTH_QS_TILE_DIALOG)) {
mDialogViewModel.showDialog(expandable);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
index 2d3120a1dcce..972b20e138d9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
@@ -29,11 +29,15 @@ import javax.inject.Inject
/**
* Provides a shortcut to start an activity from [QSTileUserActionInteractor]. It supports keyguard
- * dismissing and tile from-view animations.
+ * dismissing and tile from-view animations, as well as the option to show over lockscreen.
*/
interface QSTileIntentUserInputHandler {
- fun handle(expandable: Expandable?, intent: Intent)
+ fun handle(
+ expandable: Expandable?,
+ intent: Intent,
+ dismissShadeShowOverLockScreenWhenLocked: Boolean = false
+ )
/** @param requestLaunchingDefaultActivity used in case !pendingIndent.isActivity */
fun handle(
@@ -52,12 +56,25 @@ constructor(
private val userHandle: UserHandle,
) : QSTileIntentUserInputHandler {
- override fun handle(expandable: Expandable?, intent: Intent) {
+ override fun handle(
+ expandable: Expandable?,
+ intent: Intent,
+ dismissShadeShowOverLockScreenWhenLocked: Boolean
+ ) {
val animationController: ActivityTransitionAnimator.Controller? =
expandable?.activityTransitionController(
InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE
)
- activityStarter.postStartActivityDismissingKeyguard(intent, 0, animationController)
+ if (dismissShadeShowOverLockScreenWhenLocked) {
+ activityStarter.startActivity(
+ intent,
+ true /* dismissShade */,
+ animationController,
+ true /* showOverLockscreenWhenLocked */
+ )
+ } else {
+ activityStarter.postStartActivityDismissingKeyguard(intent, 0, animationController)
+ }
}
// TODO(b/249804373): make sure to allow showing activities over the lockscreen. See b/292112939
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
index c9c44434361d..c971f547c302 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
@@ -15,6 +15,7 @@
*/
package com.android.systemui.qs.tiles.dialog;
+import static com.android.settingslib.satellite.SatelliteDialogUtils.TYPE_IS_WIFI;
import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA;
import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_WIFI_ENTRY_COUNT;
@@ -57,6 +58,8 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.telephony.flags.Flags;
+import com.android.settingslib.satellite.SatelliteDialogUtils;
import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
import com.android.systemui.Prefs;
import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan;
@@ -73,6 +76,7 @@ import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
import kotlinx.coroutines.CoroutineScope;
+import kotlinx.coroutines.Job;
import java.util.List;
import java.util.concurrent.Executor;
@@ -161,6 +165,9 @@ public class InternetDialogDelegate implements
// Wi-Fi scanning progress bar
protected boolean mIsProgressBarVisible;
private SystemUIDialog mDialog;
+ private final CoroutineScope mCoroutineScope;
+ @Nullable
+ private Job mClickJob;
@AssistedFactory
public interface Factory {
@@ -203,7 +210,7 @@ public class InternetDialogDelegate implements
mCanConfigWifi = canConfigWifi;
mCanChangeWifiState = WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(context);
mKeyguard = keyguardStateController;
-
+ mCoroutineScope = coroutineScope;
mUiEventLogger = uiEventLogger;
mDialogTransitionAnimator = dialogTransitionAnimator;
mAdapter = new InternetAdapter(mInternetDialogController, coroutineScope);
@@ -388,11 +395,9 @@ public class InternetDialogDelegate implements
});
mConnectedWifListLayout.setOnClickListener(this::onClickConnectedWifi);
mSeeAllLayout.setOnClickListener(this::onClickSeeMoreButton);
- mWiFiToggle.setOnCheckedChangeListener(
- (buttonView, isChecked) -> {
- if (mInternetDialogController.isWifiEnabled() == isChecked) return;
- mInternetDialogController.setWifiEnabled(isChecked);
- });
+ mWiFiToggle.setOnClickListener(v -> {
+ handleWifiToggleClicked(mWiFiToggle.isChecked());
+ });
mDoneButton.setOnClickListener(v -> dialog.dismiss());
mShareWifiButton.setOnClickListener(v -> {
if (mInternetDialogController.mayLaunchShareWifiSettings(mConnectedWifiEntry, v)) {
@@ -404,6 +409,32 @@ public class InternetDialogDelegate implements
});
}
+ private void handleWifiToggleClicked(boolean isChecked) {
+ if (Flags.oemEnabledSatelliteFlag()) {
+ if (mClickJob != null && !mClickJob.isCompleted()) {
+ return;
+ }
+ mClickJob = SatelliteDialogUtils.mayStartSatelliteWarningDialog(
+ mDialog.getContext(), mCoroutineScope, TYPE_IS_WIFI, isAllowClick -> {
+ if (isAllowClick) {
+ setWifiEnable(isChecked);
+ } else {
+ mWiFiToggle.setChecked(!isChecked);
+ }
+ return null;
+ });
+ return;
+ }
+ setWifiEnable(isChecked);
+ }
+
+ private void setWifiEnable(boolean isChecked) {
+ if (mInternetDialogController.isWifiEnabled() == isChecked) {
+ return;
+ }
+ mInternetDialogController.setWifiEnabled(isChecked);
+ }
+
@MainThread
private void updateEthernet() {
mEthernetLayout.setVisibility(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt
new file mode 100644
index 000000000000..1e8ce588b4e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.qr.domain.interactor
+
+import android.os.UserHandle
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
+import com.android.systemui.qrcodescanner.controller.QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
+import com.android.systemui.qs.tiles.impl.qr.domain.model.QRCodeScannerTileModel
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+/** Observes one qr scanner state changes providing the [QRCodeScannerTileModel]. */
+class QRCodeScannerTileDataInteractor
+@Inject
+constructor(
+ @Background private val bgCoroutineContext: CoroutineContext,
+ @Application private val scope: CoroutineScope,
+ private val qrController: QRCodeScannerController,
+) : QSTileDataInteractor<QRCodeScannerTileModel> {
+ override fun tileData(
+ user: UserHandle,
+ triggers: Flow<DataUpdateTrigger>
+ ): Flow<QRCodeScannerTileModel> =
+ conflatedCallbackFlow {
+ qrController.registerQRCodeScannerChangeObservers(DEFAULT_QR_CODE_SCANNER_CHANGE)
+ val callback =
+ object : QRCodeScannerController.Callback {
+ override fun onQRCodeScannerActivityChanged() {
+ trySend(generateModel())
+ }
+ }
+ qrController.addCallback(callback)
+ awaitClose {
+ qrController.removeCallback(callback)
+ qrController.unregisterQRCodeScannerChangeObservers(
+ DEFAULT_QR_CODE_SCANNER_CHANGE
+ )
+ }
+ }
+ .onStart { emit(generateModel()) }
+ .flowOn(bgCoroutineContext)
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ QRCodeScannerTileModel.TemporarilyUnavailable
+ )
+
+ override fun availability(user: UserHandle): Flow<Boolean> =
+ flowOf(qrController.isCameraAvailable)
+
+ private fun generateModel(): QRCodeScannerTileModel {
+ val intent = qrController.intent
+
+ return if (qrController.isAbleToLaunchScannerActivity && intent != null)
+ QRCodeScannerTileModel.Available(intent)
+ else QRCodeScannerTileModel.TemporarilyUnavailable
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractor.kt
new file mode 100644
index 000000000000..7c0c41eca4bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractor.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.qr.domain.interactor
+
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.interactor.QSTileInput
+import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.qr.domain.model.QRCodeScannerTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import javax.inject.Inject
+
+/** Handles qr tile clicks. */
+class QRCodeScannerTileUserActionInteractor
+@Inject
+constructor(
+ private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+) : QSTileUserActionInteractor<QRCodeScannerTileModel> {
+
+ override suspend fun handleInput(input: QSTileInput<QRCodeScannerTileModel>): Unit =
+ with(input) {
+ when (action) {
+ is QSTileUserAction.Click -> {
+ when (data) {
+ is QRCodeScannerTileModel.Available ->
+ qsTileIntentUserActionHandler.handle(
+ action.expandable,
+ data.intent,
+ true
+ )
+ is QRCodeScannerTileModel.TemporarilyUnavailable -> {} // no-op
+ }
+ }
+ is QSTileUserAction.LongClick -> {} // no-op
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/model/QRCodeScannerTileModel.kt
index 4e40042a49b0..22c9b66b2806 100644
--- a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/model/QRCodeScannerTileModel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -13,22 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.contrast
-import android.app.Activity
-import android.os.Bundle
-import javax.inject.Inject
+package com.android.systemui.qs.tiles.impl.qr.domain.model
-/** Trampoline activity responsible for creating a [ContrastDialogDelegate] */
-class ContrastDialogActivity
-@Inject
-constructor(
- private val contrastDialogDelegate : ContrastDialogDelegate
-) : Activity() {
+import android.content.Intent
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- contrastDialogDelegate.createDialog().show()
- finish()
- }
+/** qr scanner tile model. */
+sealed interface QRCodeScannerTileModel {
+ data class Available(val intent: Intent) : QRCodeScannerTileModel
+ data object TemporarilyUnavailable : QRCodeScannerTileModel
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapper.kt
new file mode 100644
index 000000000000..45a77179fb3f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapper.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.qr.ui
+
+import android.content.res.Resources
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
+import com.android.systemui.qs.tiles.impl.qr.domain.model.QRCodeScannerTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+/** Maps [QRCodeScannerTileModel] to [QSTileState]. */
+class QRCodeScannerTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Resources.Theme,
+) : QSTileDataToStateMapper<QRCodeScannerTileModel> {
+
+ override fun map(config: QSTileConfig, data: QRCodeScannerTileModel): QSTileState =
+ QSTileState.build(resources, theme, config.uiConfig) {
+ label = resources.getString(R.string.qr_code_scanner_title)
+ contentDescription = label
+ icon = {
+ Icon.Loaded(resources.getDrawable(R.drawable.ic_qr_code_scanner, theme), null)
+ }
+ sideViewIcon = QSTileState.SideViewIcon.Chevron
+ supportedActions = setOf(QSTileState.UserAction.CLICK)
+
+ when (data) {
+ is QRCodeScannerTileModel.Available -> {
+ activationState = QSTileState.ActivationState.INACTIVE
+ secondaryLabel = null
+ }
+ is QRCodeScannerTileModel.TemporarilyUnavailable -> {
+ activationState = QSTileState.ActivationState.UNAVAILABLE
+ secondaryLabel =
+ resources.getString(R.string.qr_code_scanner_updating_secondary_label)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java
index 5e561cfb14a1..ee1944e0b5cf 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java
@@ -45,6 +45,7 @@ import androidx.customview.widget.ExploreByTouchHelper;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.Flags;
import com.android.systemui.res.R;
import java.util.List;
@@ -378,8 +379,14 @@ public class CropView extends View {
upper = 1;
break;
}
- Log.i(TAG, "getAllowedValues: " + boundary + ", "
- + "result=[lower=" + lower + ", upper=" + upper + "]");
+ if (lower >= upper) {
+ Log.wtf(TAG, "getAllowedValues computed an invalid range "
+ + "[" + lower + ", " + upper + "]");
+ if (Flags.screenshotScrollCropViewCrashFix()) {
+ lower = Math.min(lower, upper);
+ upper = lower;
+ }
+ }
return new Range<>(lower, upper);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallBackgroundContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainer.kt
index ce88a5f5e55f..cae86a652245 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallBackgroundContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainer.kt
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone.ongoingcall
+package com.android.systemui.statusbar.chips.ui.view
import android.content.Context
import android.util.AttributeSet
import com.android.systemui.animation.view.LaunchableLinearLayout
/**
- * A container view for the ongoing call chip background. Needed so that we can limit the height of
- * the background when the font size is very large (200%), in which case the background would go
+ * A container view for the ongoing activity chip background. Needed so that we can limit the height
+ * of the background when the font size is very large (200%), in which case the background would go
* past the bounds of the status bar.
*/
-class OngoingCallBackgroundContainer(context: Context, attrs: AttributeSet) :
+class ChipBackgroundContainer(context: Context, attrs: AttributeSet) :
LaunchableLinearLayout(context, attrs) {
/** Sets where this view should fetch its max height from. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometer.kt
index bb7ba4c4174f..ff3061e850d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometer.kt
@@ -14,36 +14,34 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone.ongoingcall
+package com.android.systemui.statusbar.chips.ui.view
import android.content.Context
import android.util.AttributeSet
-
import android.widget.Chronometer
import androidx.annotation.UiThread
/**
- * A [Chronometer] specifically for the ongoing call chip in the status bar.
+ * A [Chronometer] specifically for chips in the status bar that show ongoing duration of an
+ * activity.
*
* This class handles:
- * 1) Setting the text width. If we used a basic WRAP_CONTENT for width, the chip width would
- * change slightly each second because the width of each number is slightly different.
- *
- * Instead, we save the largest number width seen so far and ensure that the chip is at least
- * that wide. This means the chip may get larger over time (e.g. in the transition from 59:59
- * to 1:00:00), but never smaller.
+ * 1) Setting the text width. If we used a basic WRAP_CONTENT for width, the chip width would change
+ * slightly each second because the width of each number is slightly different.
*
- * 2) Hiding the text if the time gets too long for the space available. Once the text has been
- * hidden, it remains hidden for the duration of the call.
+ * Instead, we save the largest number width seen so far and ensure that the chip is at least
+ * that wide. This means the chip may get larger over time (e.g. in the transition from 59:59 to
+ * 1:00:00), but never smaller.
+ * 2) Hiding the text if the time gets too long for the space available. Once the text has been
+ * hidden, it remains hidden for the duration of the activity.
*
* Note that if the text was too big in portrait mode, resulting in the text being hidden, then the
* text will also be hidden in landscape (even if there is enough space for it in landscape).
*/
-class OngoingCallChronometer @JvmOverloads constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyle: Int = 0
-) : Chronometer(context, attrs, defStyle) {
+class ChipChronometer
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
+ Chronometer(context, attrs, defStyle) {
// Minimum width that the text view can be. Corresponds with the largest number width seen so
// far.
@@ -53,8 +51,8 @@ class OngoingCallChronometer @JvmOverloads constructor(
private var shouldHideText: Boolean = false
override fun setBase(base: Long) {
- // These variables may have changed during the previous call, so re-set them before the new
- // call starts.
+ // These variables may have changed during the previous activity, so re-set them before the
+ // new activity starts.
minimumTextWidth = 0
shouldHideText = false
visibility = VISIBLE
@@ -75,9 +73,7 @@ class OngoingCallChronometer @JvmOverloads constructor(
}
// Evaluate how wide the text *wants* to be if it had unlimited space.
- super.onMeasure(
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- heightMeasureSpec)
+ super.onMeasure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightMeasureSpec)
val desiredTextWidth = measuredWidth
// Evaluate how wide the text *can* be based on the enforced constraints
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index 968b591b9a09..5a616dfd1f63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification.footer.ui.view;
import static android.graphics.PorterDuff.Mode.SRC_ATOP;
-import static com.android.systemui.Flags.notificationBackgroundTintOptimization;
+import static com.android.systemui.Flags.notificationFooterBackgroundTintOptimization;
import static com.android.systemui.util.ColorUtilKt.hexColorString;
import android.annotation.ColorInt;
@@ -407,7 +407,7 @@ public class FooterView extends StackScrollerDecorView {
final Drawable clearAllBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
final Drawable manageBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
final @ColorInt int scHigh;
- if (!notificationBackgroundTintOptimization()) {
+ if (!notificationFooterBackgroundTintOptimization()) {
scHigh = Utils.getColorAttrDefaultColor(mContext,
com.android.internal.R.attr.materialColorSurfaceContainerHigh);
if (scHigh != 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
index a901c5f8ae2a..87f11f131f32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.interruption
+import android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST
import android.app.Notification
import android.app.Notification.BubbleMetadata
import android.app.Notification.CATEGORY_EVENT
@@ -23,6 +24,8 @@ import android.app.Notification.CATEGORY_REMINDER
import android.app.Notification.VISIBILITY_PRIVATE
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.database.ContentObserver
import android.hardware.display.AmbientDisplayConfiguration
import android.os.Handler
@@ -234,6 +237,7 @@ class AvalancheSuppressor(
private val avalancheProvider: AvalancheProvider,
private val systemClock: SystemClock,
private val systemSettings: SystemSettings,
+ private val packageManager: PackageManager,
) :
VisualInterruptionFilter(
types = setOf(PEEK, PULSE),
@@ -249,6 +253,7 @@ class AvalancheSuppressor(
ALLOW_CATEGORY_EVENT,
ALLOW_FSI_WITH_PERMISSION_ON,
ALLOW_COLORIZED,
+ ALLOW_EMERGENCY,
SUPPRESS
}
@@ -299,13 +304,20 @@ class AvalancheSuppressor(
if (entry.sbn.notification.isColorized) {
return State.ALLOW_COLORIZED
}
+ if (entry.sbn.notification.isColorized) {
+ return State.ALLOW_COLORIZED
+ }
+ if (
+ packageManager.checkPermission(RECEIVE_EMERGENCY_BROADCAST, entry.sbn.packageName) ==
+ PERMISSION_GRANTED
+ ) {
+ return State.ALLOW_EMERGENCY
+ }
return State.SUPPRESS
}
private fun isCooldownEnabled(): Boolean {
- return systemSettings.getInt(
- Settings.System.NOTIFICATION_COOLDOWN_ENABLED,
- /* def */ 1
- ) == 1
+ return systemSettings.getInt(Settings.System.NOTIFICATION_COOLDOWN_ENABLED, /* def */ 1) ==
+ 1
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
index e6d97c211dc5..f68e194aace2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.statusbar.notification.interruption
+import android.content.pm.PackageManager
import android.hardware.display.AmbientDisplayConfiguration
import android.os.Handler
import android.os.PowerManager
@@ -63,7 +64,8 @@ constructor(
private val uiEventLogger: UiEventLogger,
private val userTracker: UserTracker,
private val avalancheProvider: AvalancheProvider,
- private val systemSettings: SystemSettings
+ private val systemSettings: SystemSettings,
+ private val packageManager: PackageManager
) : VisualInterruptionDecisionProvider {
init {
@@ -172,7 +174,9 @@ constructor(
addFilter(AlertKeyguardVisibilitySuppressor(keyguardNotificationVisibilityProvider))
if (NotificationAvalancheSuppression.isEnabled) {
- addFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings))
+ addFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ )
avalancheProvider.register()
}
started = true
@@ -232,14 +236,17 @@ constructor(
private fun makeLoggablePeekDecision(entry: NotificationEntry): LoggableDecision =
checkConditions(PEEK)
- ?: checkFilters(PEEK, entry) ?: checkSuppressInterruptions(entry)
- ?: checkSuppressAwakeInterruptions(entry) ?: checkSuppressAwakeHeadsUp(entry)
- ?: LoggableDecision.unsuppressed
+ ?: checkFilters(PEEK, entry)
+ ?: checkSuppressInterruptions(entry)
+ ?: checkSuppressAwakeInterruptions(entry)
+ ?: checkSuppressAwakeHeadsUp(entry)
+ ?: LoggableDecision.unsuppressed
private fun makeLoggablePulseDecision(entry: NotificationEntry): LoggableDecision =
checkConditions(PULSE)
- ?: checkFilters(PULSE, entry) ?: checkSuppressInterruptions(entry)
- ?: LoggableDecision.unsuppressed
+ ?: checkFilters(PULSE, entry)
+ ?: checkSuppressInterruptions(entry)
+ ?: LoggableDecision.unsuppressed
override fun makeAndLogBubbleDecision(entry: NotificationEntry): Decision =
traceSection("VisualInterruptionDecisionProviderImpl#makeAndLogBubbleDecision") {
@@ -252,8 +259,10 @@ constructor(
private fun makeLoggableBubbleDecision(entry: NotificationEntry): LoggableDecision =
checkConditions(BUBBLE)
- ?: checkFilters(BUBBLE, entry) ?: checkSuppressInterruptions(entry)
- ?: checkSuppressAwakeInterruptions(entry) ?: LoggableDecision.unsuppressed
+ ?: checkFilters(BUBBLE, entry)
+ ?: checkSuppressInterruptions(entry)
+ ?: checkSuppressAwakeInterruptions(entry)
+ ?: LoggableDecision.unsuppressed
private fun logDecision(
type: VisualInterruptionType,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt
index db3cf5abe618..9d0fcd3acceb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.row
import android.app.Flags
+import android.os.SystemProperties
import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
import javax.inject.Inject
@@ -34,8 +35,13 @@ constructor(private val statusBarModeRepositoryStore: StatusBarModeRepositorySto
HeadsUpStyleProvider {
override fun shouldApplyCompactStyle(): Boolean {
- // Use compact HUN for immersive mode.
- return Flags.compactHeadsUpNotification() &&
- statusBarModeRepositoryStore.defaultDisplay.isInFullscreenMode.value
+ return Flags.compactHeadsUpNotification() && (isInImmersiveMode() || alwaysShow())
}
+
+ private fun isInImmersiveMode() =
+ statusBarModeRepositoryStore.defaultDisplay.isInFullscreenMode.value
+
+ /** developer setting to always show Minimal HUN, even if the device is not in full screen */
+ private fun alwaysShow() =
+ SystemProperties.getBoolean("persist.compact_heads_up_notification.always_show", false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
index d4f8ea385667..d6c73a9dda9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
@@ -23,8 +23,8 @@ import com.android.systemui.flags.RefactorFlagUtils
/** Helper for reading or using the heads-up cycling flag state. */
@Suppress("NOTHING_TO_INLINE")
object NotificationHeadsUpCycling {
- /** The aconfig flag name */
- const val FLAG_NAME = Flags.FLAG_NOTIFICATION_HEADS_UP_CYCLING
+ /** The aconfig flag name - enable this feature when FLAG_NOTIFICATION_THROTTLE_HUN is on. */
+ const val FLAG_NAME = Flags.FLAG_NOTIFICATION_THROTTLE_HUN
/** A token used for dependency declaration */
val token: FlagToken
@@ -33,7 +33,7 @@ object NotificationHeadsUpCycling {
/** Is the heads-up cycling animation enabled */
@JvmStatic
inline val isEnabled
- get() = Flags.notificationHeadsUpCycling()
+ get() = Flags.notificationThrottleHun()
/** Whether to animate the bottom line when transiting from a tall HUN to a short HUN */
@JvmStatic
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 abbe7d74733d..17b54c8f3970 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
@@ -674,7 +674,7 @@ public class NotificationStackScrollLayout
void setOverExpansion(float margin) {
mAmbientState.setOverExpansion(margin);
if (notificationOverExpansionClippingFix() && !SceneContainerFlag.isEnabled()) {
- setRoundingClippingYTranslation((int) margin);
+ setRoundingClippingYTranslation(mShouldUseSplitNotificationShade ? (int) margin : 0);
}
updateStackPosition();
requestChildrenUpdate();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 4fc11df5aaa5..a858fb079d72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -119,7 +119,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private MultiSourceMinAlphaController mEndSideAlphaController;
private LinearLayout mEndSideContent;
private View mClockView;
- private View mOngoingCallChip;
+ private View mOngoingActivityChip;
private View mNotificationIconAreaInner;
// Visibilities come in from external system callers via disable flags, but we also sometimes
// modify the visibilities internally. We need to store both so that we don't accidentally
@@ -345,7 +345,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mEndSideContent = mStatusBar.findViewById(R.id.status_bar_end_side_content);
mEndSideAlphaController = new MultiSourceMinAlphaController(mEndSideContent);
mClockView = mStatusBar.findViewById(R.id.clock);
- mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
+ mOngoingActivityChip = mStatusBar.findViewById(R.id.ongoing_activity_chip);
showEndSideContent(false);
showClock(false);
initOperatorName();
@@ -594,9 +594,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
// so if the icons are disabled then the call chip should be, too.)
boolean showOngoingCallChip = hasOngoingCall && !disableNotifications;
if (showOngoingCallChip) {
- showOngoingCallChip(animate);
+ showOngoingActivityChip(animate);
} else {
- hideOngoingCallChip(animate);
+ hideOngoingActivityChip(animate);
}
mOngoingCallController.notifyChipVisibilityChanged(showOngoingCallChip);
}
@@ -688,14 +688,19 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
animateShow(mClockView, animate);
}
- /** Hides the ongoing call chip. */
- public void hideOngoingCallChip(boolean animate) {
- animateHiddenState(mOngoingCallChip, View.GONE, animate);
+ /** Hides the ongoing activity chip. */
+ private void hideOngoingActivityChip(boolean animate) {
+ animateHiddenState(mOngoingActivityChip, View.GONE, animate);
}
- /** Displays the ongoing call chip. */
- public void showOngoingCallChip(boolean animate) {
- animateShow(mOngoingCallChip, animate);
+ /**
+ * Displays the ongoing activity chip.
+ *
+ * For now, this chip will only ever contain the ongoing call information, but after b/332662551
+ * feature is implemented, it will support different kinds of ongoing activities.
+ */
+ private void showOngoingActivityChip(boolean animate) {
+ animateShow(mOngoingActivityChip, animate);
}
/**
@@ -803,7 +808,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private void initOngoingCallChip() {
mOngoingCallController.addCallback(mOngoingCallListener);
- mOngoingCallController.setChipView(mOngoingCallChip);
+ mOngoingCallController.setChipView(mOngoingActivityChip);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index ec88b6c56477..a7d4ce30a191 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -36,6 +36,8 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.chips.ui.view.ChipChronometer
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -145,8 +147,8 @@ class OngoingCallController @Inject constructor(
fun setChipView(chipView: View) {
tearDownChipView()
this.chipView = chipView
- val backgroundView: OngoingCallBackgroundContainer? =
- chipView.findViewById(R.id.ongoing_call_chip_background)
+ val backgroundView: ChipBackgroundContainer? =
+ chipView.findViewById(R.id.ongoing_activity_chip_background)
backgroundView?.maxHeightFetcher = { statusBarWindowController.statusBarHeight }
if (hasOngoingCall()) {
updateChip()
@@ -226,7 +228,7 @@ class OngoingCallController @Inject constructor(
if (callNotificationInfo == null) { return }
val currentChipView = chipView
val backgroundView =
- currentChipView?.findViewById<View>(R.id.ongoing_call_chip_background)
+ currentChipView?.findViewById<View>(R.id.ongoing_activity_chip_background)
val intent = callNotificationInfo?.intent
if (currentChipView != null && backgroundView != null && intent != null) {
currentChipView.setOnClickListener {
@@ -271,8 +273,8 @@ class OngoingCallController @Inject constructor(
@VisibleForTesting
fun tearDownChipView() = chipView?.getTimeView()?.stop()
- private fun View.getTimeView(): OngoingCallChronometer? {
- return this.findViewById(R.id.ongoing_call_chip_time)
+ private fun View.getTimeView(): ChipChronometer? {
+ return this.findViewById(R.id.ongoing_activity_chip_time)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
index 9c78ab42a14a..886481e64dbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 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.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
index d4b2dbff078b..2e54972c4950 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
@@ -53,6 +53,27 @@ constructor(
)
}
+ fun logTopLevelServiceStateBroadcastEmergencyOnly(subId: Int, serviceState: ServiceState) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ bool1 = serviceState.isEmergencyOnly
+ },
+ { "ACTION_SERVICE_STATE for subId=$int1. ServiceState.isEmergencyOnly=$bool1" }
+ )
+ }
+
+ fun logTopLevelServiceStateBroadcastMissingExtras(subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { int1 = subId },
+ { "ACTION_SERVICE_STATE for subId=$int1. Intent is missing extras. Ignoring" }
+ )
+ }
+
fun logOnSignalStrengthsChanged(signalStrength: SignalStrength, subId: Int) {
buffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ServiceStateModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ServiceStateModel.kt
new file mode 100644
index 000000000000..cce3eb02023b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ServiceStateModel.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.model
+
+import android.telephony.ServiceState
+
+/**
+ * Simplified representation of a [ServiceState] for use in SystemUI. Add any fields that we need to
+ * extract from service state here for consumption downstream
+ */
+data class ServiceStateModel(val isEmergencyOnly: Boolean) {
+ companion object {
+ fun fromServiceState(serviceState: ServiceState): ServiceStateModel {
+ return ServiceStateModel(isEmergencyOnly = serviceState.isEmergencyOnly)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
index 9471574fc755..5ad8bf1652b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
@@ -21,6 +21,7 @@ import android.telephony.SubscriptionManager
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.MobileMappings.Config
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -92,6 +93,19 @@ interface MobileConnectionsRepository {
val defaultMobileIconGroup: Flow<MobileIconGroup>
/**
+ * [deviceServiceState] is equivalent to the last [Intent.ACTION_SERVICE_STATE] broadcast with a
+ * subscriptionId of -1 (aka [SubscriptionManager.INVALID_SUBSCRIPTION_ID]).
+ *
+ * While each [MobileConnectionsRepository] listens for the service state of each subscription,
+ * there is potentially a service state associated with the device itself. This value can be
+ * used to calculate e.g., the emergency calling capability of the device (as opposed to the
+ * emergency calling capability of an individual mobile connection)
+ *
+ * Note: this is a [StateFlow] using an eager sharing strategy.
+ */
+ val deviceServiceState: StateFlow<ServiceStateModel?>
+
+ /**
* If any active SIM on the device is in
* [android.telephony.TelephonyManager.SIM_STATE_PIN_REQUIRED] or
* [android.telephony.TelephonyManager.SIM_STATE_PUK_REQUIRED] or
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
index 8a8e33efbcef..b0681525a137 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
@@ -25,6 +25,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.demomode.DemoMode
import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
@@ -151,6 +152,15 @@ constructor(
override val defaultMobileIconGroup: Flow<SignalIcon.MobileIconGroup> =
activeRepo.flatMapLatest { it.defaultMobileIconGroup }
+ override val deviceServiceState: StateFlow<ServiceStateModel?> =
+ activeRepo
+ .flatMapLatest { it.deviceServiceState }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ realRepository.deviceServiceState.value
+ )
+
override val isAnySimSecure: Flow<Boolean> = activeRepo.flatMapLatest { it.isAnySimSecure }
override fun getIsAnySimSecure(): Boolean = activeRepo.value.getIsAnySimSecure()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index 2b3c6326032c..a944e9133a31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -27,6 +27,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
@@ -136,6 +137,9 @@ constructor(
override val defaultMobileIconGroup = flowOf(TelephonyIcons.THREE_G)
+ // TODO(b/339023069): demo command for device-based connectivity state
+ override val deviceServiceState: StateFlow<ServiceStateModel?> = MutableStateFlow(null)
+
override val isAnySimSecure: Flow<Boolean> = flowOf(getIsAnySimSecure())
override fun getIsAnySimSecure(): Boolean = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 0073e9cd3dd8..c32f0e8090ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -18,8 +18,10 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
import android.annotation.SuppressLint
import android.content.Context
+import android.content.Intent
import android.content.IntentFilter
import android.telephony.CarrierConfigManager
+import android.telephony.ServiceState
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
@@ -35,7 +37,6 @@ import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings.Config
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.BroadcastDispatcher
-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
@@ -47,6 +48,7 @@ import com.android.systemui.statusbar.pipeline.airplane.data.repository.Airplane
import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
@@ -55,6 +57,7 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.Connectivi
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.util.kotlin.pairwise
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import java.io.PrintWriter
import java.lang.ref.WeakReference
import javax.inject.Inject
@@ -68,6 +71,7 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
@@ -169,6 +173,35 @@ constructor(
}
.flowOn(bgDispatcher)
+ /** Note that this flow is eager, so we don't miss any state */
+ override val deviceServiceState: StateFlow<ServiceStateModel?> =
+ broadcastDispatcher
+ .broadcastFlow(IntentFilter(Intent.ACTION_SERVICE_STATE)) { intent, _ ->
+ val subId =
+ intent.getIntExtra(
+ SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
+ INVALID_SUBSCRIPTION_ID
+ )
+
+ val extras = intent.extras
+ if (extras == null) {
+ logger.logTopLevelServiceStateBroadcastMissingExtras(subId)
+ return@broadcastFlow null
+ }
+
+ val serviceState = ServiceState.newFromBundle(extras)
+ logger.logTopLevelServiceStateBroadcastEmergencyOnly(subId, serviceState)
+ if (subId == INVALID_SUBSCRIPTION_ID) {
+ // Assume that -1 here is the device's service state. We don't care about
+ // other ones.
+ ServiceStateModel.fromServiceState(serviceState)
+ } else {
+ null
+ }
+ }
+ .filterNotNull()
+ .stateIn(scope, SharingStarted.Eagerly, null)
+
/**
* State flow that emits the set of mobile data subscriptions, each represented by its own
* [SubscriptionModel].
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 91d7ca65b30d..cc4d5689c3fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -111,6 +111,13 @@ interface MobileIconsInteractor {
val isForceHidden: Flow<Boolean>
/**
+ * True if the device-level service state (with -1 subscription id) reports emergency calls
+ * only. This value is only useful when there are no other subscriptions OR all existing
+ * subscriptions report that they are not in service.
+ */
+ val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean>
+
+ /**
* Vends out a [MobileIconInteractor] tracking the [MobileConnectionRepository] for the given
* subId.
*/
@@ -377,6 +384,9 @@ constructor(
.map { it.contains(ConnectivitySlot.MOBILE) }
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ override val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean> =
+ mobileConnectionsRepo.deviceServiceState.map { it?.isEmergencyOnly ?: false }
+
/** Vends out new [MobileIconInteractor] for a particular subId */
override fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
reuseCache[subId]?.get() ?: createMobileConnectionInteractorForSubId(subId)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
index 51c053ee284a..5b954b272044 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
@@ -19,6 +19,9 @@ package com.android.systemui.statusbar.pipeline.satellite.domain.interactor
import com.android.internal.telephony.flags.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.OemSatelliteInputLog
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.satellite.data.DeviceBasedSatelliteRepository
import com.android.systemui.statusbar.pipeline.satellite.shared.model.SatelliteConnectionState
@@ -45,6 +48,7 @@ constructor(
deviceProvisioningInteractor: DeviceProvisioningInteractor,
wifiInteractor: WifiInteractor,
@Application scope: CoroutineScope,
+ @OemSatelliteInputLog private val logBuffer: LogBuffer,
) {
/** Must be observed by any UI showing Satellite iconography */
val isSatelliteAllowed =
@@ -79,25 +83,52 @@ constructor(
val isWifiActive: Flow<Boolean> =
wifiInteractor.wifiNetwork.map { it is WifiNetworkModel.Active }
+ private val allConnectionsOos =
+ iconsInteractor.icons.aggregateOver(
+ selector = { intr ->
+ combine(intr.isInService, intr.isEmergencyOnly, intr.isNonTerrestrial) {
+ isInService,
+ isEmergencyOnly,
+ isNtn ->
+ !isInService && !isEmergencyOnly && !isNtn
+ }
+ },
+ defaultValue = true, // no connections == everything is OOS
+ ) { isOosAndNotEmergencyAndNotSatellite ->
+ isOosAndNotEmergencyAndNotSatellite.all { it }
+ }
+
/** When all connections are considered OOS, satellite connectivity is potentially valid */
val areAllConnectionsOutOfService =
if (Flags.oemEnabledSatelliteFlag()) {
- iconsInteractor.icons.aggregateOver(
- selector = { intr ->
- combine(intr.isInService, intr.isEmergencyOnly, intr.isNonTerrestrial) {
- isInService,
- isEmergencyOnly,
- isNtn ->
- !isInService && !(isEmergencyOnly || isNtn)
- }
- }
- ) { isOosAndNotEmergencyOnlyOrSatellite ->
- isOosAndNotEmergencyOnlyOrSatellite.all { it }
+ combine(
+ allConnectionsOos,
+ iconsInteractor.isDeviceInEmergencyCallsOnlyMode,
+ ) { connectionsOos, deviceEmergencyOnly ->
+ logBuffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ bool1 = connectionsOos
+ bool2 = deviceEmergencyOnly
+ },
+ {
+ "Updating OOS status. allConnectionsOOs=$bool1 " +
+ "deviceEmergencyOnly=$bool2"
+ },
+ )
+ // If no connections exist, or all are OOS, then we look to the device-based
+ // service state to detect if any calls are possible
+ connectionsOos && !deviceEmergencyOnly
}
} else {
flowOf(false)
}
.stateIn(scope, SharingStarted.WhileSubscribed(), true)
+
+ companion object {
+ const val TAG = "DeviceBasedSatelliteInteractor"
+ }
}
/**
@@ -106,12 +137,22 @@ constructor(
*
* Provides a way to connect the reactivity of the top-level flow with the reactivity of an
* arbitrarily-defined relationship ([selector]) from R to the flow that R exposes.
+ *
+ * [defaultValue] allows for a default value to be used if there are no leaf nodes after applying
+ * [selector]. E.g., if there are no mobile connections, assume that there is no service.
*/
@OptIn(ExperimentalCoroutinesApi::class)
private inline fun <R, reified S, T> Flow<List<R>>.aggregateOver(
crossinline selector: (R) -> Flow<S>,
- crossinline transform: (Array<S>) -> T
+ defaultValue: T,
+ crossinline transform: (Array<S>) -> T,
): Flow<T> {
return map { list -> list.map { selector(it) } }
- .flatMapLatest { newFlows -> combine(newFlows) { newVals -> transform(newVals) } }
+ .flatMapLatest { newFlows ->
+ if (newFlows.isEmpty()) {
+ flowOf(defaultValue)
+ } else {
+ combine(newFlows) { newVals -> transform(newVals) }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
index f44e7f3da6f0..8b48bd32e089 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -22,6 +22,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
import com.android.systemui.statusbar.policy.BaseHeadsUpManager.HeadsUpEntry
+import com.android.systemui.util.Compile
import java.io.PrintWriter
import javax.inject.Inject
@@ -37,7 +38,7 @@ constructor(
) : Dumpable {
private val tag = "AvalancheController"
- private val debug = false
+ private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG)
// HUN showing right now, in the floating state where full shade is hidden, on launcher or AOD
@VisibleForTesting var headsUpEntryShowing: HeadsUpEntry? = null
@@ -108,7 +109,10 @@ constructor(
if (isOnlyNextEntry) {
// HeadsUpEntry.updateEntry recursively calls AvalancheController#update
// and goes to the isShowing case above
- headsUpEntryShowing!!.updateEntry(false, "avalanche duration update")
+ headsUpEntryShowing!!.updateEntry(
+ /* updatePostTime= */ false,
+ /* updateEarliestRemovalTime= */ false,
+ /* reason= */ "avalanche duration update")
}
}
logState("after $fn")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index b8318a7dfb61..a7fe49b54602 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -39,6 +39,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -114,7 +115,8 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
mUiEventLogger = uiEventLogger;
mAvalancheController = avalancheController;
Resources resources = context.getResources();
- mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
+ mMinimumDisplayTime = NotificationThrottleHun.isEnabled()
+ ? 500 : resources.getInteger(R.integer.heads_up_notification_minimum_time);
mStickyForSomeTimeAutoDismissTime = resources.getInteger(
R.integer.sticky_heads_up_notification_time);
mAutoDismissTime = resources.getInteger(R.integer.heads_up_notification_decay);
@@ -765,11 +767,23 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
* @param updatePostTime whether or not to refresh the post time
*/
public void updateEntry(boolean updatePostTime, @Nullable String reason) {
+ updateEntry(updatePostTime, /* updateEarliestRemovalTime= */ true, reason);
+ }
+
+ /**
+ * Updates an entry's removal time.
+ * @param updatePostTime whether or not to refresh the post time
+ * @param updateEarliestRemovalTime whether this update should further delay removal
+ */
+ public void updateEntry(boolean updatePostTime, boolean updateEarliestRemovalTime,
+ @Nullable String reason) {
Runnable runnable = () -> {
mLogger.logUpdateEntry(mEntry, updatePostTime, reason);
final long now = mSystemClock.elapsedRealtime();
- mEarliestRemovalTime = now + mMinimumDisplayTime;
+ if (updateEarliestRemovalTime) {
+ mEarliestRemovalTime = now + mMinimumDisplayTime;
+ }
if (updatePostTime) {
mPostTime = Math.max(mPostTime, now);
@@ -785,7 +799,9 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
FinishTimeUpdater finishTimeCalculator = () -> {
final long finishTime = calculateFinishTime();
final long now = mSystemClock.elapsedRealtime();
- final long timeLeft = Math.max(finishTime - now, mMinimumDisplayTime);
+ final long timeLeft = NotificationThrottleHun.isEnabled()
+ ? Math.max(finishTime, mEarliestRemovalTime) - now
+ : Math.max(finishTime - now, mMinimumDisplayTime);
return timeLeft;
};
scheduleAutoRemovalCallback(finishTimeCalculator, "updateEntry (not sticky)");
@@ -818,13 +834,6 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
}
public int compareNonTimeFields(HeadsUpEntry headsUpEntry) {
- boolean isPinned = mEntry.isRowPinned();
- boolean otherPinned = headsUpEntry.mEntry.isRowPinned();
- if (isPinned && !otherPinned) {
- return -1;
- } else if (!isPinned && otherPinned) {
- return 1;
- }
boolean selfFullscreen = hasFullScreenIntent(mEntry);
boolean otherFullscreen = hasFullScreenIntent(headsUpEntry.mEntry);
if (selfFullscreen && !otherFullscreen) {
@@ -851,6 +860,13 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
}
public int compareTo(@NonNull HeadsUpEntry headsUpEntry) {
+ boolean isPinned = mEntry.isRowPinned();
+ boolean otherPinned = headsUpEntry.mEntry.isRowPinned();
+ if (isPinned && !otherPinned) {
+ return -1;
+ } else if (!isPinned && otherPinned) {
+ return 1;
+ }
int nonTimeCompareResult = compareNonTimeFields(headsUpEntry);
if (nonTimeCompareResult != 0) {
return nonTimeCompareResult;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
index e0df1e0e5586..2d5e3a6788cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.graphics.PointF;
-import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
@@ -40,7 +39,6 @@ import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import androidx.test.filters.SmallTest;
-import com.android.systemui.Flags;
import com.android.systemui.Prefs;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.utils.TestUtils;
@@ -230,7 +228,6 @@ public class MenuAnimationControllerTest extends SysuiTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_FLOATING_MENU_ANIMATED_TUCK)
public void tuck_animates() {
mMenuAnimationController.cancelAnimations();
mMenuAnimationController.moveToEdgeAndHide();
@@ -239,7 +236,6 @@ public class MenuAnimationControllerTest extends SysuiTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_FLOATING_MENU_ANIMATED_TUCK)
public void untuck_animates() {
mMenuAnimationController.cancelAnimations();
mMenuAnimationController.moveOutEdgeAndShow();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt
deleted file mode 100644
index ab034652e0cc..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.contrast
-
-import android.app.UiModeManager
-import android.app.UiModeManager.ContrastUtils.fromContrastLevel
-import android.os.Looper
-import android.provider.Settings
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper.RunWithLooper
-import android.view.LayoutInflater
-import android.view.View
-import android.widget.FrameLayout
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.DialogTransitionAnimator
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.model.SysUiState
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.settings.SecureSettings
-import com.android.systemui.util.time.FakeSystemClock
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.Mock
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-/** Test the behaviour of buttons of the [ContrastDialogDelegate]. */
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@RunWithLooper
-class ContrastDialogDelegateTest : SysuiTestCase() {
-
- private val mainExecutor = FakeExecutor(FakeSystemClock())
- private lateinit var mContrastDialogDelegate: ContrastDialogDelegate
- @Mock private lateinit var sysuiDialogFactory: SystemUIDialog.Factory
- @Mock private lateinit var sysuiDialog: SystemUIDialog
- @Mock private lateinit var mockUiModeManager: UiModeManager
- @Mock private lateinit var mockUserTracker: UserTracker
- @Mock private lateinit var mockSecureSettings: SecureSettings
- @Mock private lateinit var sysuiState: SysUiState
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- mDependency.injectTestDependency(FeatureFlags::class.java, FakeFeatureFlags())
- mDependency.injectTestDependency(SysUiState::class.java, sysuiState)
- mDependency.injectMockDependency(DialogTransitionAnimator::class.java)
- whenever(sysuiState.setFlag(any(), any())).thenReturn(sysuiState)
- whenever(sysuiDialogFactory.create(any(SystemUIDialog.Delegate::class.java)))
- .thenReturn(sysuiDialog)
- whenever(sysuiDialog.layoutInflater).thenReturn(LayoutInflater.from(mContext))
-
- whenever(mockUserTracker.userId).thenReturn(context.userId)
- if (Looper.myLooper() == null) Looper.prepare()
-
- mContrastDialogDelegate =
- ContrastDialogDelegate(
- sysuiDialogFactory,
- mainExecutor,
- mockUiModeManager,
- mockUserTracker,
- mockSecureSettings
- )
-
- mContrastDialogDelegate.createDialog()
- val viewCaptor = ArgumentCaptor.forClass(View::class.java)
- verify(sysuiDialog).setView(viewCaptor.capture())
- whenever(sysuiDialog.requireViewById(anyInt()) as View?).then {
- viewCaptor.value.requireViewById(it.getArgument(0))
- }
- }
-
- @Test
- fun testClickButtons_putsContrastInSettings() {
- mContrastDialogDelegate.onCreate(sysuiDialog, null)
-
- mContrastDialogDelegate.contrastButtons.forEach {
- (contrastLevel: Int, clickedButton: FrameLayout) ->
- clickedButton.performClick()
- mainExecutor.runAllReady()
- verify(mockSecureSettings)
- .putFloatForUser(
- eq(Settings.Secure.CONTRAST_LEVEL),
- eq(fromContrastLevel(contrastLevel)),
- eq(context.userId)
- )
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index 53560d740575..48a5df91d47c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -25,16 +25,19 @@ import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
import com.android.app.animation.Interpolators
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.util.KeyguardTransitionRunner
+import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -45,6 +48,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.dropWhile
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.After
@@ -372,6 +377,43 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
assertThat(wtfHandler.failed).isTrue()
}
+ @Test
+ fun simulateRaceConditionIsProcessedInOrder() =
+ testScope.runTest {
+ val ktr = KeyguardTransitionRepositoryImpl(kosmos.testDispatcher)
+ val steps by collectValues(ktr.transitions.dropWhile { step -> step.from == OFF })
+
+ // Add a delay to the first transition in order to attempt to have the second transition
+ // be processed first
+ val info1 = TransitionInfo(OWNER_NAME, AOD, LOCKSCREEN, animator = null)
+ launch {
+ ktr.forceDelayForRaceConditionTest = true
+ ktr.startTransition(info1)
+ }
+ val info2 = TransitionInfo(OWNER_NAME, LOCKSCREEN, OCCLUDED, animator = null)
+ launch {
+ ktr.forceDelayForRaceConditionTest = false
+ ktr.startTransition(info2)
+ }
+
+ runCurrent()
+ assertThat(steps.isEmpty()).isTrue()
+
+ advanceTimeBy(60L)
+ assertThat(steps[0])
+ .isEqualTo(
+ TransitionStep(info1.from, info1.to, 0f, TransitionState.STARTED, OWNER_NAME)
+ )
+ assertThat(steps[1])
+ .isEqualTo(
+ TransitionStep(info1.from, info1.to, 0f, TransitionState.CANCELED, OWNER_NAME)
+ )
+ assertThat(steps[2])
+ .isEqualTo(
+ TransitionStep(info2.from, info2.to, 0f, TransitionState.STARTED, OWNER_NAME)
+ )
+ }
+
private fun listWithStep(
step: BigDecimal,
start: BigDecimal = BigDecimal.ZERO,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 00f94a57a2d1..fa3fe5c80adb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -1669,7 +1669,9 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
// THEN a transition from DOZING => OCCLUDED should occur
assertThat(transitionRepository)
.startedTransition(
- ownerName = "FromDozingTransitionInteractor",
+ ownerName =
+ "FromDozingTransitionInteractor" +
+ "(keyguardInteractor.onCameraLaunchDetected)",
from = KeyguardState.DOZING,
to = KeyguardState.OCCLUDED,
animatorAssertion = { it.isNotNull() },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
index db275ec190ac..db36131b825e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
@@ -52,7 +52,7 @@ class ActivityTaskManagerThumbnailLoaderTest : SysuiTestCase() {
val taskId = 123
val isLowResolution = false
val snapshot = createTaskSnapshot()
- val thumbnailData = ThumbnailData(snapshot)
+ val thumbnailData = ThumbnailData.fromSnapshot(snapshot)
whenever(activityManager.getTaskThumbnail(taskId, isLowResolution))
.thenReturn(thumbnailData)
@@ -74,7 +74,7 @@ class ActivityTaskManagerThumbnailLoaderTest : SysuiTestCase() {
fun captureThumbnail_thumbnailAvailable_returnsThumbnailData() =
testScope.runTest {
val taskId = 321
- val thumbnailData = ThumbnailData(createTaskSnapshot())
+ val thumbnailData = ThumbnailData.fromSnapshot(createTaskSnapshot())
whenever(activityManager.takeTaskThumbnail(taskId)).thenReturn(thumbnailData)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt
index 629c663943db..bc947fb910e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt
@@ -3,6 +3,7 @@ package com.android.systemui.qs
import android.content.ComponentName
import android.service.quicksettings.Tile
import android.testing.AndroidTestingRunner
+import android.widget.Switch
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.qs.QSTile
@@ -66,15 +67,19 @@ class TileStateToProtoTest : SysuiTestCase() {
assertThat(proto?.hasBooleanState()).isFalse()
}
+ /**
+ * The [QSTile.AdapterState.expandedAccessibilityClassName] setting to [Switch] results in the
+ * proto having a booleanState. The value of that boolean is true iff the tile is active.
+ */
@Test
- fun booleanState_ACTIVE() {
+ fun adapterState_ACTIVE() {
val state =
- QSTile.BooleanState().apply {
+ QSTile.AdapterState().apply {
spec = TEST_SPEC
label = TEST_LABEL
secondaryLabel = TEST_SUBTITLE
state = Tile.STATE_ACTIVE
- value = true
+ expandedAccessibilityClassName = Switch::class.java.name
}
val proto = state.toProto()
@@ -89,6 +94,33 @@ class TileStateToProtoTest : SysuiTestCase() {
assertThat(proto?.booleanState).isTrue()
}
+ /**
+ * Similar to [adapterState_ACTIVE], the use of
+ * [QSTile.AdapterState.expandedAccessibilityClassName] signals that the tile is toggleable.
+ */
+ @Test
+ fun adapterState_INACTIVE() {
+ val state =
+ QSTile.AdapterState().apply {
+ spec = TEST_SPEC
+ label = TEST_LABEL
+ secondaryLabel = TEST_SUBTITLE
+ state = Tile.STATE_INACTIVE
+ expandedAccessibilityClassName = Switch::class.java.name
+ }
+ val proto = state.toProto()
+
+ assertThat(proto).isNotNull()
+ assertThat(proto?.hasSpec()).isTrue()
+ assertThat(proto?.spec).isEqualTo(TEST_SPEC)
+ assertThat(proto?.hasComponentName()).isFalse()
+ assertThat(proto?.label).isEqualTo(TEST_LABEL)
+ assertThat(proto?.secondaryLabel).isEqualTo(TEST_SUBTITLE)
+ assertThat(proto?.state).isEqualTo(Tile.STATE_INACTIVE)
+ assertThat(proto?.hasBooleanState()).isTrue()
+ assertThat(proto?.booleanState).isFalse()
+ }
+
@Test
fun noSpec_returnsNull() {
val state =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
index e2a3fac60ee8..ad87315c34f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
@@ -22,7 +22,7 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
-import com.android.systemui.res.R
+import com.android.internal.telephony.flags.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.classifier.FalsingManagerFake
@@ -33,10 +33,12 @@ import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.settings.GlobalSettings
import com.google.common.truth.Truth.assertThat
import dagger.Lazy
+import kotlinx.coroutines.Job
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -44,11 +46,15 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
class AirplaneModeTileTest : SysuiTestCase() {
+
@Mock
private lateinit var mHost: QSHost
@Mock
@@ -62,7 +68,9 @@ class AirplaneModeTileTest : SysuiTestCase() {
@Mock
private lateinit var mBroadcastDispatcher: BroadcastDispatcher
@Mock
- private lateinit var mConnectivityManager: Lazy<ConnectivityManager>
+ private lateinit var mLazyConnectivityManager: Lazy<ConnectivityManager>
+ @Mock
+ private lateinit var mConnectivityManager: ConnectivityManager
@Mock
private lateinit var mGlobalSettings: GlobalSettings
@Mock
@@ -72,13 +80,15 @@ class AirplaneModeTileTest : SysuiTestCase() {
private lateinit var mTestableLooper: TestableLooper
private lateinit var mTile: AirplaneModeTile
+ @Mock
+ private lateinit var mClickJob: Job
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
mTestableLooper = TestableLooper.get(this)
Mockito.`when`(mHost.context).thenReturn(mContext)
Mockito.`when`(mHost.userContext).thenReturn(mContext)
-
+ Mockito.`when`(mLazyConnectivityManager.get()).thenReturn(mConnectivityManager)
mTile = AirplaneModeTile(
mHost,
mUiEventLogger,
@@ -90,7 +100,7 @@ class AirplaneModeTileTest : SysuiTestCase() {
mActivityStarter,
mQsLogger,
mBroadcastDispatcher,
- mConnectivityManager,
+ mLazyConnectivityManager,
mGlobalSettings,
mUserTracker)
}
@@ -120,4 +130,24 @@ class AirplaneModeTileTest : SysuiTestCase() {
assertThat(state.icon)
.isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_airplane_icon_on))
}
+
+ @Test
+ fun handleClick_noSatelliteFeature_directSetAirplaneMode() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+
+ mTile.handleClick(null)
+
+ verify(mConnectivityManager).setAirplaneMode(any())
+ }
+
+ @Test
+ fun handleClick_hasSatelliteFeatureButClickIsProcessing_doNothing() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ Mockito.`when`(mClickJob.isCompleted).thenReturn(false)
+ mTile.mClickJob = mClickJob
+
+ mTile.handleClick(null)
+
+ verify(mConnectivityManager, times(0)).setAirplaneMode(any())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
index 830f08a0c445..1ffbb7be49fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
@@ -9,10 +9,11 @@ import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
+import com.android.internal.telephony.flags.Flags
import com.android.settingslib.Utils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogViewModel
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.plugins.ActivityStarter
@@ -23,13 +24,14 @@ import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogViewModel
+import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.BluetoothController
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Job
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -37,6 +39,7 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -54,7 +57,7 @@ class BluetoothTileTest : SysuiTestCase() {
@Mock private lateinit var uiEventLogger: QsEventLogger
@Mock private lateinit var featureFlags: FeatureFlagsClassic
@Mock private lateinit var bluetoothTileDialogViewModel: BluetoothTileDialogViewModel
-
+ @Mock private lateinit var clickJob: Job
private lateinit var testableLooper: TestableLooper
private lateinit var tile: FakeBluetoothTile
@@ -191,6 +194,41 @@ class BluetoothTileTest : SysuiTestCase() {
}
@Test
+ fun handleClick_hasSatelliteFeatureButNoQsTileDialogAndClickIsProcessing_doNothing() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG))
+ .thenReturn(false)
+ `when`(clickJob.isCompleted).thenReturn(false)
+ tile.mClickJob = clickJob
+
+ tile.handleClick(null)
+
+ verify(bluetoothController, times(0)).setBluetoothEnabled(any())
+ }
+
+ @Test
+ fun handleClick_noSatelliteFeatureAndNoQsTileDialog_directSetBtEnable() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG))
+ .thenReturn(false)
+
+ tile.handleClick(null)
+
+ verify(bluetoothController).setBluetoothEnabled(any())
+ }
+
+ @Test
+ fun handleClick_noSatelliteFeatureButHasQsTileDialog_showDialog() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG))
+ .thenReturn(true)
+
+ tile.handleClick(null)
+
+ verify(bluetoothTileDialogViewModel).showDialog(null)
+ }
+
+ @Test
fun testMetadataListener_whenDisconnected_isUnregistered() {
val state = QSTile.BooleanState()
val cachedDevice = mock<CachedBluetoothDevice>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
index 9ec9b69d44c0..05d9495db091 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.ExpandHelper
import com.android.systemui.SysuiTestCase
@@ -39,7 +39,7 @@ import org.mockito.Mockito.`when` as whenever
@SmallTest
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class DragDownHelperTest : SysuiTestCase() {
private lateinit var dragDownHelper: DragDownHelper
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 1504d4c1f033..995b5383c3c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -65,9 +65,9 @@ import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricSourceType;
import android.os.BatteryManager;
import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
@@ -88,7 +88,7 @@ import java.util.List;
import java.util.Set;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class KeyguardIndicationControllerTest extends KeyguardIndicationControllerBaseTest {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt
index cdc752098aa7..4a14f8853904 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
import kotlinx.coroutines.Dispatchers
@@ -28,7 +28,7 @@ import org.junit.runner.RunWith
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class KeyguardIndicationControllerWithCoroutinesTest : KeyguardIndicationControllerBaseTest() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
index 8cb530c355bd..948a73208d10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
@@ -1,7 +1,7 @@
package com.android.systemui.statusbar
-import android.testing.AndroidTestingRunner
import android.util.DisplayMetrics
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.LogBuffer
@@ -16,7 +16,7 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class LSShadeTransitionLoggerTest : SysuiTestCase() {
lateinit var logger: LSShadeTransitionLogger
@@ -41,4 +41,4 @@ class LSShadeTransitionLoggerTest : SysuiTestCase() {
// log a non-null, non row, ensure no crash
logger.logDragDownStarted(view)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
index d3befb4ad4cd..fe2dd6d78a82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar
-import android.testing.AndroidTestingRunner
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -28,7 +28,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import java.util.function.Consumer
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class LightRevealScrimTest : SysuiTestCase() {
@@ -85,4 +85,4 @@ class LightRevealScrimTest : SysuiTestCase() {
private const val DEFAULT_WIDTH = 42
private const val DEFAULT_HEIGHT = 24
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
index 402d9aab66bd..e48242a3e003 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -36,7 +36,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class LockscreenShadeQsTransitionControllerTest : SysuiTestCase() {
private val configurationController = FakeConfigurationController()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index a92cf8c96339..69e8f4737a5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,9 +1,9 @@
package com.android.systemui.statusbar
import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.ExpandHelper
import com.android.systemui.SysUITestModule
@@ -74,7 +74,7 @@ private fun <T> anyObject(): T {
@SmallTest
@RunWithLooper(setAsMainLooper = true)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index d3febf55117b..ef1c927f22d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -32,8 +32,8 @@ import android.os.UserHandle;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -52,7 +52,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class NotificationListenerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
private static final int TEST_UID = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index d3850be7c192..c9d910c530ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -27,9 +27,9 @@ import android.app.Notification;
import android.content.Context;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -52,7 +52,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class NotificationRemoteInputManagerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index fc0c85e30d5a..9f94cff4ead4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -17,11 +17,11 @@
package com.android.systemui.statusbar
import android.os.IBinder
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.Choreographer
import android.view.View
import android.view.ViewRootImpl
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ShadeInterpolation
@@ -59,7 +59,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
@SmallTest
class NotificationShadeDepthControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
index 49e5c456e645..9907740672ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -43,7 +43,7 @@ import org.mockito.Mockito.`when` as whenever
@SmallTest
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class PulseExpansionHandlerTest : SysuiTestCase() {
private lateinit var pulseExpansionHandler: PulseExpansionHandler
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
index ce11d6a62a8c..58943ea3b4ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
@@ -27,9 +27,9 @@ import android.app.RemoteInputHistoryItem;
import android.net.Uri;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -44,7 +44,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class RemoteInputNotificationRebuilderTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
index 2606be5fabad..6b9a19a92fc4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
@@ -1,7 +1,7 @@
package com.android.systemui.statusbar
import org.mockito.Mockito.`when` as whenever
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
@@ -14,7 +14,7 @@ import org.mockito.Mockito.intThat
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class SingleShadeLockScreenOverScrollerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 775dc3c95746..3346e19b4ce9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -29,9 +29,9 @@ import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -52,7 +52,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@SmallTest
public class SmartReplyControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt
index 700fb1ec332c..58473c4e07a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt
@@ -1,7 +1,7 @@
package com.android.systemui.statusbar
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -23,7 +23,7 @@ import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper
class SplitShadeLockScreenOverScrollerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
index 79a2008e7542..26692c908c5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertEquals
@@ -24,7 +24,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class StatusBarStateEventTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
index b90582575970..78c1887f7c0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
@@ -5,9 +5,9 @@ import android.os.UserHandle
import android.os.VibrationAttributes
import android.os.VibrationEffect
import android.os.Vibrator
-import android.testing.AndroidTestingRunner
import android.view.HapticFeedbackConstants
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.eq
@@ -26,7 +26,7 @@ import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import java.util.concurrent.Executor
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class VibratorHelperTest : SysuiTestCase() {
@@ -120,4 +120,4 @@ class VibratorHelperTest : SysuiTestCase() {
return verify(vibrator)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallBackgroundContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
index f0a457e2c19f..7d2b463afab7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallBackgroundContainerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone.ongoingcall
+package com.android.systemui.statusbar.chips.ui.view
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.View
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -31,16 +31,17 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
-class OngoingCallBackgroundContainerTest : SysuiTestCase() {
+class ChipBackgroundContainerTest : SysuiTestCase() {
- private lateinit var underTest: OngoingCallBackgroundContainer
+ private lateinit var underTest: ChipBackgroundContainer
@Before
fun setUp() {
allowTestableLooperAsMainThread()
TestableLooper.get(this).runWithLooper {
- val chipView = LayoutInflater.from(context).inflate(R.layout.ongoing_call_chip, null)
- underTest = chipView.requireViewById(R.id.ongoing_call_chip_background)
+ val chipView =
+ LayoutInflater.from(context).inflate(R.layout.ongoing_activity_chip, null)
+ underTest = chipView.requireViewById(R.id.ongoing_activity_chip_background)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
index 7e25aa373097..b8d4e47544dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone.ongoingcall
+package com.android.systemui.statusbar.chips.ui.view
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.View
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -38,17 +38,18 @@ private const val XL_TEXT = "00:0000"
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
-class OngoingCallChronometerTest : SysuiTestCase() {
+class ChipChronometerTest : SysuiTestCase() {
- private lateinit var textView: OngoingCallChronometer
+ private lateinit var textView: ChipChronometer
private lateinit var doesNotFitText: String
@Before
fun setUp() {
allowTestableLooperAsMainThread()
TestableLooper.get(this).runWithLooper {
- val chipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_call_chip, null)
- textView = chipView.findViewById(R.id.ongoing_call_chip_time)!!
+ val chipView =
+ LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip, null)
+ textView = chipView.findViewById(R.id.ongoing_activity_chip_time)!!
measureTextView()
calculateDoesNotFixText()
}
@@ -159,8 +160,8 @@ class OngoingCallChronometerTest : SysuiTestCase() {
private fun measureTextView() {
textView.measure(
- View.MeasureSpec.makeMeasureSpec(TEXT_VIEW_MAX_WIDTH, View.MeasureSpec.AT_MOST),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ View.MeasureSpec.makeMeasureSpec(TEXT_VIEW_MAX_WIDTH, View.MeasureSpec.AT_MOST),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
index 7e88ae080178..643acdbb9277 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.connectivity
import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.lifecycle.Lifecycle
import com.android.systemui.SysuiTestCase
@@ -42,7 +42,7 @@ import org.mockito.MockitoAnnotations
import java.util.concurrent.Executor
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
class AccessPointControllerImplTest : SysuiTestCase() {
@@ -244,4 +244,4 @@ class AccessPointControllerImplTest : SysuiTestCase() {
verify(wifiEntryOther).connect(any())
verify(callback, never()).onSettingsActivityTriggered(any())
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.kt
index 7aed4f7e250b..40f81e2bae5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.kt
@@ -15,7 +15,7 @@
*/
package com.android.systemui.statusbar.connectivity
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
@@ -26,7 +26,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class MobileStateTest : SysuiTestCase() {
private val state = MobileState()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
index 461d80412cb5..4241254e1fb9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
@@ -39,10 +39,10 @@ import android.os.Looper;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.settingslib.SignalIcon.MobileIconGroup;
@@ -60,7 +60,7 @@ import org.junit.runner.RunWith;
import java.util.HashMap;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class NetworkControllerDataTest extends NetworkControllerBaseTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java
index 3bbf06dbc69c..521cb4f4c42d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java
@@ -19,9 +19,9 @@ package com.android.systemui.statusbar.connectivity;
import static junit.framework.Assert.assertEquals;
import android.net.NetworkCapabilities;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -30,7 +30,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class NetworkControllerEthernetTest extends NetworkControllerBaseTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
index 35609a5faf00..22f0e9d20c41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
@@ -33,10 +33,10 @@ import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.settingslib.graph.SignalDrawable;
@@ -59,7 +59,7 @@ import java.util.Collections;
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
index 44a1c50e5a58..6c80a97625a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
@@ -34,9 +34,9 @@ import android.net.NetworkInfo;
import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.settingslib.mobile.TelephonyIcons;
@@ -50,7 +50,7 @@ import org.mockito.Mockito;
import java.util.Collections;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
// These match the constants in WifiManager and need to be kept up to date.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
index 5bf0a94935cf..3eeed73a539c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.connectivity
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.systemui.SysuiTestCase
@@ -26,7 +26,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class NetworkTypeResIdCacheTest : SysuiTestCase() {
private lateinit var cache: NetworkTypeResIdCache
private var overrides = MobileIconCarrierIdOverridesFake()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
index 452302d4db8a..984bda1c0d21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
@@ -19,11 +19,11 @@ package com.android.systemui.statusbar.events
import android.content.Context
import android.graphics.Insets
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.Gravity
import android.view.View
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.AnimatorTestRule
@@ -46,7 +46,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class SystemEventChipAnimationControllerTest : SysuiTestCase() {
private lateinit var controller: SystemEventChipAnimationController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
index ae84df55e113..742494b769de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.statusbar.events
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
@@ -40,7 +40,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
index cacfa8dc0be4..376873d19624 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
@@ -19,10 +19,10 @@ package com.android.systemui.statusbar.events
import android.graphics.Insets
import android.graphics.Rect
import android.os.Process
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.View
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.AnimatorTestRule
@@ -54,7 +54,7 @@ import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
index d3f5adeb05bb..0f58990d4310 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
@@ -1,9 +1,9 @@
package com.android.systemui.statusbar.gesture
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.InputEvent
import android.view.MotionEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.FakeDisplayTracker
@@ -13,7 +13,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class GenericGestureDetectorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
index 6b2ee76a75ac..01a0fd020bda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
@@ -19,11 +19,11 @@ package com.android.systemui.statusbar.notification;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.widget.FrameLayout;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -36,7 +36,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class AboveShelfObserverTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
index fc4702c209e1..d66b010daefd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
@@ -42,9 +42,9 @@ import android.os.Handler;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -58,7 +58,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class AssistantFeedbackControllerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test_package";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
index 0103564088e0..77fd06757595 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
@@ -25,12 +25,12 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -56,7 +56,7 @@ import java.util.List;
import java.util.Map;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class DynamicChildBindControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
index 5b72ca07edbe..d879fcecffab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
@@ -25,9 +25,9 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -38,9 +38,10 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
@SmallTest
-@org.junit.runner.RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class DynamicPrivacyControllerTest extends SysuiTestCase {
@@ -127,4 +128,4 @@ public class DynamicPrivacyControllerTest extends SysuiTestCase {
mDynamicPrivacyController.onUnlockedChanged();
verifyNoMoreInteractions(mListener);
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
index 1cce3b5b9e77..8e8a3513f3be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
@@ -18,8 +18,8 @@ package com.android.systemui.statusbar.notification
import android.provider.DeviceConfig
import android.provider.Settings
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito
@@ -39,7 +39,7 @@ import org.mockito.Mockito.`when`
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class NotificationSectionsFeatureManagerTest : SysuiTestCase() {
var manager: NotificationSectionsFeatureManager? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
index 3b3f05d25c16..3abdf6212f22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
@@ -1,9 +1,9 @@
package com.android.systemui.statusbar.notification
import android.app.Notification.GROUP_ALERT_SUMMARY
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -35,7 +35,7 @@ import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class NotificationTransitionAnimatorControllerTest : SysuiTestCase() {
@Mock lateinit var notificationListContainer: NotificationListContainer
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
index 1aac515f538b..a5206f52b6f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.LogBuffer
@@ -28,7 +28,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class NotificationWakeUpCoordinatorLoggerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
index 67b540cd762e..0906d8eadf44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.notification
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
@@ -60,7 +60,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
@OptIn(ExperimentalCoroutinesApi::class)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt
index 7d8cf3657ba1..382b307fb9de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt
@@ -2,6 +2,7 @@ package com.android.systemui.statusbar.notification
import android.platform.test.annotations.EnableFlags
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation
@@ -10,13 +11,12 @@ import com.android.systemui.util.mockito.whenever
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class RoundableTest : SysuiTestCase() {
private val targetView: View = mock()
private val roundable = FakeRoundable(targetView = targetView)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index 2d044fec1eb6..8e95ac599ce1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -30,8 +30,8 @@ import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.NotificationChannel;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -51,7 +51,7 @@ import java.util.Arrays;
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class HighPriorityProviderTest extends SysuiTestCase {
@Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
@Mock private GroupMembershipManager mGroupMembershipManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
index 892575ab6c71..2a587511eaec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.notification.collection
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.lifecycle.Observer
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -34,7 +34,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class NotifLiveDataImplTest : SysuiTestCase() {
@@ -164,4 +164,4 @@ class NotifLiveDataImplTest : SysuiTestCase() {
assertThat(executor.runAllReady()).isEqualTo(2)
verifyNoMoreInteractions(syncObserver, asyncObserver)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
index 9c8ac5cded9e..d87f827de776 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.notification.collection
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -30,7 +30,7 @@ import org.junit.runner.RunWith
import java.lang.UnsupportedOperationException
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class NotifLiveDataStoreImplTest : SysuiTestCase() {
@@ -102,4 +102,4 @@ class NotifLiveDataStoreImplTest : SysuiTestCase() {
liveDataStoreImpl.setActiveNotifList(mutableListOf(entry1, entry2))
executor.runAllReady()
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
index 3b908b4175f9..f1da22f08e75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.notification.collection
-import android.testing.AndroidTestingRunner
import android.view.Choreographer
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dagger.SysUISingleton
@@ -36,7 +36,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class NotifPipelineChoreographerTest : SysuiTestCase() {
val viewChoreographer: Choreographer = mock()
@@ -118,4 +118,4 @@ interface NotifPipelineChoreographerTestComponent {
@BindsInstance @Main executor: DelayableExecutor
): NotifPipelineChoreographerTestComponent
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 8a48fe10d7fc..72d1db3affe8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -46,8 +46,8 @@ import android.os.UserHandle;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -64,7 +64,7 @@ import org.mockito.Mockito;
import java.util.ArrayList;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class NotificationEntryTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
private static final int TEST_UID = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
index ab55a7d650c6..1fd6b042ad67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
@@ -20,7 +20,7 @@ import android.os.UserHandle
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
@@ -47,7 +47,7 @@ import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class SectionStyleProviderTest : SysuiTestCase() {
@Rule @JvmField public val setFlagsRule = SetFlagsRule()
@@ -118,4 +118,4 @@ class SectionStyleProviderTest : SysuiTestCase() {
override fun getSection(): NotifSection? = NotifSection(inputSectioner, 1)
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt
index 4708350c1c0a..2ad3c9e1c21a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt
@@ -25,7 +25,7 @@ import android.os.Bundle
import android.os.UserHandle
import android.service.notification.NotificationListenerService.Ranking
import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -48,7 +48,7 @@ private const val PACKAGE = "pkg"
private const val USER_ID = -1
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class TargetSdkResolverTest : SysuiTestCase() {
private val packageManager: PackageManager = mock()
private val applicationInfo = ApplicationInfo().apply { targetSdkVersion = SDK_VERSION }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
index b1180aebe9bd..f029a2ca6099 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
@@ -30,8 +30,8 @@ import static java.util.Objects.requireNonNull;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -57,7 +57,7 @@ import java.util.Arrays;
import java.util.Collections;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class GroupCoalescerTest extends SysuiTestCase {
private GroupCoalescer mCoalescer;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
index f2207afeda10..1f2925528077 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
@@ -30,9 +30,9 @@ import android.app.Person;
import android.content.Intent;
import android.graphics.Color;
import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -47,7 +47,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class ColorizedFgsCoordinatorTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
index 59fc591e4d06..e72109d4d8e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
@@ -39,7 +39,7 @@ import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations.initMocks
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class DataStoreCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: DataStoreCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
index f91e5a8cf626..543f0c72a8ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import android.app.Notification
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -38,7 +38,7 @@ import org.mockito.Mockito
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class DismissibilityCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: DismissibilityCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
index a544cad03b77..4d5ea92aa0e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -49,7 +49,7 @@ import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class DreamCoordinatorTest : SysuiTestCase() {
@Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
@Mock private lateinit var notifPipeline: NotifPipeline
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
index 929c3d4288d4..7b688d4f91fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
@@ -36,7 +36,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations.initMocks
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class GroupCountCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: GroupCountCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
index eac0e296c51f..3f140265e5f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import android.app.Notification
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.SbnBuilder
@@ -45,7 +45,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations.initMocks
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class GroupWhenCoordinatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
index a652ad64ea8d..7fe97d27f273 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -42,7 +42,7 @@ import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations.initMocks
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class GutsCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: GutsCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index cd75e0811fff..8e9323fead92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -17,8 +17,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.app.Notification.GROUP_ALERT_ALL
import android.app.Notification.GROUP_ALERT_SUMMARY
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.logcatLogBuffer
@@ -70,7 +70,7 @@ import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class HeadsUpCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: HeadsUpCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
index 27542a462d36..5dcad4bb9e62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
@@ -24,9 +24,9 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.util.SparseArray;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -47,7 +47,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class HideNotifsForOtherUsersCoordinatorTest extends SysuiTestCase {
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index 5ff73538b359..25533d82608b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -20,7 +20,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.app.Notification
import android.os.UserHandle
import android.provider.Settings
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -67,7 +67,7 @@ import kotlin.time.Duration.Companion.seconds
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class KeyguardCoordinatorTest : SysuiTestCase() {
private val headsUpManager: HeadsUpManager = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
index e90a3ac8bfdc..07c29a024a6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
@@ -33,8 +33,8 @@ import android.media.session.MediaSession;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.service.notification.NotificationListenerService;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
@@ -58,7 +58,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public final class MediaCoordinatorTest extends SysuiTestCase {
private MediaSession mMediaSession;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
index c29ff416feb9..501bca248c76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
@@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.platform.test.annotations.EnableFlags
import android.service.notification.NotificationListenerService.REASON_CANCEL
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.NotifPipeline
@@ -36,7 +36,7 @@ import org.junit.runner.RunWith
import org.mockito.Mockito.verify
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
class NotificationStatsLoggerCoordinatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
index cceaaea672c4..80127682be02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
@@ -39,10 +39,10 @@ import static java.util.Objects.requireNonNull;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
@@ -88,7 +88,7 @@ import java.util.List;
import java.util.Map;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class PreparationCoordinatorTest extends SysuiTestCase {
private NotifCollectionListener mCollectionListener;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index 3d1253e2b05d..c05b13163d32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -35,9 +35,9 @@ import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
-import android.testing.AndroidTestingRunner;
import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -67,7 +67,7 @@ import java.util.ArrayList;
import java.util.Arrays;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class RankingCoordinatorTest extends SysuiTestCase {
@Mock private StatusBarStateController mStatusBarStateController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
index d3df48e9ef02..deb3fc1224ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
@@ -23,8 +23,8 @@ import android.os.Handler
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -54,7 +54,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations.initMocks
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class RemoteInputCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: RemoteInputCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
index 7daadb07f89a..1b7ec5381713 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
@@ -37,7 +37,7 @@ import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations.initMocks
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class RowAlertTimeCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: RowAlertTimeCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
index a66f8ce1a92c..5b231e21e700 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.AssistantFeedbackController
@@ -41,7 +41,7 @@ import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations.initMocks
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class RowAppearanceCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: RowAppearanceCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
index 56f16f32ec15..ccf7cdd70675 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
@@ -17,8 +17,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.service.notification.NotificationListenerService.REASON_APP_CANCEL
import android.service.notification.NotificationListenerService.REASON_CANCEL
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.logcatLogBuffer
@@ -40,7 +40,7 @@ import java.util.concurrent.Executor
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class ShadeEventCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: ShadeEventCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
index ea4f692ef4f1..c7513de7a41a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
@@ -17,8 +17,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING
import com.android.systemui.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX
@@ -51,7 +51,7 @@ import org.mockito.MockitoAnnotations.initMocks
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class StackCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: StackCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
index b1d2ea21f7fc..c8fbe61fa799 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
@@ -40,7 +40,7 @@ import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class ViewConfigCoordinatorTest : SysuiTestCase() {
private lateinit var coordinator: ViewConfigCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
index 8e6ceccbc14e..7943872558c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
@@ -20,8 +20,8 @@ import android.os.Handler
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING
import com.android.systemui.SysuiTestCase
@@ -54,7 +54,7 @@ import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class NotifUiAdjustmentProviderTest : SysuiTestCase() {
private val lockscreenUserManager: NotificationLockscreenUserManager = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
index 1cdd023dd01c..d2057703d560 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
@@ -15,9 +15,9 @@
*/
package com.android.systemui.statusbar.notification.collection.listbuilder
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.util.Log
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertFalse
@@ -27,7 +27,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class SemiStableSortTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
index 20369546d68a..49f836fe9f81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.statusbar.notification.collection.listbuilder
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.listbuilder.ShadeListBuilderHelper.getContiguousSubLists
@@ -25,7 +25,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class ShadeListBuilderHelperTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
index 22f6bdc54b85..341a51e32a46 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.notifcollection
import android.service.notification.NotificationListenerService.RankingMap
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.logcatLogBuffer
@@ -34,7 +34,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class NotifCollectionInconsistencyTrackerTest : SysuiTestCase() {
private val logger = spy(NotifCollectionLogger(logcatLogBuffer()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
index a09f3a35c308..99e55a85344a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.notification.collection.notifcollection
import android.os.Handler
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -41,7 +41,7 @@ import java.util.function.Consumer
import java.util.function.Predicate
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class SelfTrackingLifetimeExtenderTest : SysuiTestCase() {
private lateinit var extender: TestableSelfTrackingLifetimeExtender
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
index b56f8e9364c4..586b947d5299 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
@@ -15,7 +15,7 @@
*/
package com.android.systemui.statusbar.notification.collection.provider
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
@@ -29,7 +29,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class VisualStabilityProviderTest : SysuiTestCase() {
private val visualStabilityProvider = VisualStabilityProvider()
private val listener: OnReorderingAllowedListener = mock()
@@ -148,4 +148,4 @@ class VisualStabilityProviderTest : SysuiTestCase() {
visualStabilityProvider.isReorderingAllowed = true
verify(selfAddingListener, times(2)).onReorderingAllowed()
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
index eeabc744987b..9d3e2e8dfcb4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
@@ -16,10 +16,10 @@
package com.android.systemui.statusbar.notification.collection.render
import android.content.Context
-import android.testing.AndroidTestingRunner
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.logcatLogBuffer
@@ -34,7 +34,7 @@ import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ShadeViewDifferTest : SysuiTestCase() {
private lateinit var differ: ShadeViewDiffer
private val rootController = FakeController(mContext, "RootController")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt
index 2a3c1a53559e..39085295fbac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt
@@ -15,7 +15,7 @@
package com.android.systemui.statusbar.notification.domain.interactor
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -25,7 +25,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class SeenNotificationsInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
index 4ac9dc2be161..bfa816e65eb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
@@ -30,8 +30,8 @@ import android.graphics.drawable.Icon
import android.os.Bundle
import android.os.SystemClock
import android.os.UserHandle
-import android.testing.AndroidTestingRunner
import androidx.test.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapperTest.Companion.any
@@ -53,7 +53,7 @@ import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class IconManagerTest : SysuiTestCase() {
companion object {
private const val TEST_PACKAGE_NAME = "test"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
index b410b33b97d9..c9f2addfd39b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
@@ -15,7 +15,7 @@
package com.android.systemui.statusbar.notification.icon.domain.interactor
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysUITestComponent
import com.android.systemui.SysUITestModule
@@ -52,7 +52,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class NotificationIconsInteractorTest : SysuiTestCase() {
private val bubbles: Bubbles = mock()
@@ -151,7 +151,7 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
}
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
private val bubbles: Bubbles = mock()
@@ -256,7 +256,7 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
}
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class StatusBarNotificationIconsInteractorTest : SysuiTestCase() {
private val bubbles: Bubbles = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
index 60eea9beb2e0..af2789b8401a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
@@ -26,9 +26,9 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import androidx.core.os.CancellationSignal;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.util.NotificationMessagingUtil;
@@ -47,7 +47,7 @@ import org.mockito.MockitoAnnotations;
import java.util.concurrent.atomic.AtomicReference;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class HeadsUpViewBinderTest extends SysuiTestCase {
private HeadsUpViewBinder mViewBinder;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
index 86620480fa7b..19214fb831eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
@@ -42,9 +42,9 @@ import android.content.Context;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -86,7 +86,7 @@ import java.util.Map;
import java.util.function.Consumer;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
private static final int NOTIF_USER_ID = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 7ade053720e9..3e8461a225b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -60,8 +60,8 @@ import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.testing.UiEventLoggerFake;
@@ -96,7 +96,7 @@ import java.util.Set;
* Tests for the interruption state provider which understands whether the system & notification
* is in a state allowing a particular notification to hun, pulse, or bubble.
*/
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
index 7ed33126a54f..a6177e8feb1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.notification.interruption
import android.platform.test.annotations.DisableFlags
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
@@ -34,7 +34,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@DisableFlags(VisualInterruptionRefactor.FLAG_NAME)
class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() {
override val provider by lazy {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
index edab9d9f7fdf..eeb51a684d42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
@@ -16,11 +16,13 @@
package com.android.systemui.statusbar.notification.interruption
+import android.Manifest.permission
import android.app.Notification.CATEGORY_EVENT
import android.app.Notification.CATEGORY_REMINDER
import android.app.NotificationManager
+import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.BUBBLE
@@ -28,9 +30,11 @@ import com.android.systemui.statusbar.notification.interruption.VisualInterrupti
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.`when`
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionProviderTestBase() {
override val provider by lazy {
@@ -51,7 +55,8 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro
uiEventLogger,
userTracker,
avalancheProvider,
- systemSettings
+ systemSettings,
+ packageManager
)
}
@@ -83,14 +88,18 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro
fun testAvalancheFilter_duringAvalanche_allowConversationFromAfterEvent() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- isConversation = true
- isImportantConversation = false
- whenMs = whenAgo(5)
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isConversation = true
+ isImportantConversation = false
+ whenMs = whenAgo(5)
+ }
+ )
}
}
@@ -98,14 +107,18 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro
fun testAvalancheFilter_duringAvalanche_suppressConversationFromBeforeEvent() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldNotHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_DEFAULT
- isConversation = true
- isImportantConversation = false
- whenMs = whenAgo(15)
- })
+ assertShouldNotHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_DEFAULT
+ isConversation = true
+ isImportantConversation = false
+ whenMs = whenAgo(15)
+ }
+ )
}
}
@@ -113,12 +126,16 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro
fun testAvalancheFilter_duringAvalanche_allowHighPriorityConversation() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- isImportantConversation = true
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isImportantConversation = true
+ }
+ )
}
}
@@ -126,12 +143,16 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro
fun testAvalancheFilter_duringAvalanche_allowCall() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- isCall = true
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isCall = true
+ }
+ )
}
}
@@ -139,12 +160,16 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro
fun testAvalancheFilter_duringAvalanche_allowCategoryReminder() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- category = CATEGORY_REMINDER
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ category = CATEGORY_REMINDER
+ }
+ )
}
}
@@ -152,12 +177,16 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro
fun testAvalancheFilter_duringAvalanche_allowCategoryEvent() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- category = CATEGORY_EVENT
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ category = CATEGORY_EVENT
+ }
+ )
}
}
@@ -165,7 +194,9 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro
fun testAvalancheFilter_duringAvalanche_allowFsi() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
assertFsiNotSuppressed()
}
}
@@ -174,16 +205,44 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro
fun testAvalancheFilter_duringAvalanche_allowColorized() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- isColorized = true
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isColorized = true
+ }
+ )
}
}
@Test
+ fun testAvalancheFilter_duringAvalanche_allowEmergency() {
+ avalancheProvider.startTime = whenAgo(10)
+
+ `when`(
+ packageManager.checkPermission(
+ org.mockito.Mockito.eq(permission.RECEIVE_EMERGENCY_BROADCAST),
+ anyString()
+ )
+ ).thenReturn(PERMISSION_GRANTED)
+
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
+ ensurePeekState()
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ }
+ )
+ }
+ }
+
+
+ @Test
fun testPeekCondition_suppressesOnlyPeek() {
withCondition(TestCondition(types = setOf(PEEK)) { true }) {
assertPeekSuppressed()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
index 3b979a7c1386..71e7dc522e20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
@@ -42,6 +42,7 @@ import android.app.PendingIntent
import android.app.PendingIntent.FLAG_MUTABLE
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.content.pm.UserInfo
import android.graphics.drawable.Icon
import android.hardware.display.FakeAmbientDisplayConfiguration
@@ -129,6 +130,7 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() {
protected val userTracker = FakeUserTracker()
protected val avalancheProvider: AvalancheProvider = mock()
lateinit var systemSettings: SystemSettings
+ protected val packageManager: PackageManager = mock()
protected abstract val provider: VisualInterruptionDecisionProvider
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
index 60aaa646fced..61c008b55ad0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
@@ -15,11 +15,11 @@
*/
package com.android.systemui.statusbar.notification.interruption
+import android.content.pm.PackageManager
import android.hardware.display.AmbientDisplayConfiguration
import android.os.Handler
import android.os.PowerManager
import com.android.internal.logging.UiEventLogger
-import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.settings.UserTracker
@@ -53,7 +53,8 @@ object VisualInterruptionDecisionProviderTestUtil {
uiEventLogger: UiEventLogger,
userTracker: UserTracker,
avalancheProvider: AvalancheProvider,
- systemSettings: SystemSettings
+ systemSettings: SystemSettings,
+ packageManager: PackageManager,
): VisualInterruptionDecisionProvider {
return if (VisualInterruptionRefactor.isEnabled) {
VisualInterruptionDecisionProviderImpl(
@@ -73,7 +74,8 @@ object VisualInterruptionDecisionProviderTestUtil {
uiEventLogger,
userTracker,
avalancheProvider,
- systemSettings
+ systemSettings,
+ packageManager
)
} else {
NotificationInterruptStateProviderWrapper(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
index 2662c80dce1d..59741718476f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
@@ -22,9 +22,9 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
@@ -44,7 +44,7 @@ import org.mockito.MockitoAnnotations;
import java.util.Collections;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class ExpansionStateLoggerTest extends SysuiTestCase {
private static final String NOTIFICATION_KEY = "notin_key";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 111309112f61..a8929a63a812 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -35,9 +35,9 @@ import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.InstanceId;
@@ -87,7 +87,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@DisableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
public class NotificationLoggerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt
index 4b0b4b89fad4..3ea7732bdf15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt
@@ -21,8 +21,8 @@ import android.app.StatsManager
import android.graphics.Bitmap
import android.graphics.drawable.Icon
import android.stats.sysui.NotificationEnums
-import android.testing.AndroidTestingRunner
import android.util.StatsEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.assertLogsWtf
@@ -46,7 +46,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class NotificationMemoryLoggerTest : SysuiTestCase() {
@Rule @JvmField val expect = Expect.create()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt
index 072a497f1a65..f10a52a73586 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt
@@ -24,8 +24,8 @@ import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Icon
import android.stats.sysui.NotificationEnums
-import android.testing.AndroidTestingRunner
import android.widget.RemoteViews
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.NotificationUtils
@@ -36,7 +36,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class NotificationMemoryMeterTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt
index 4bb28ae46211..d7dde96baf32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt
@@ -3,9 +3,9 @@ package com.android.systemui.statusbar.notification.logging
import android.app.Notification
import android.graphics.Bitmap
import android.graphics.drawable.Icon
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.widget.RemoteViews
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder
@@ -17,7 +17,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class NotificationMemoryViewWalkerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
index 9b9cb8213c91..9f98fd4c8508 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
@@ -17,9 +17,9 @@ package com.android.systemui.statusbar.notification.row
import android.annotation.ColorInt
import android.graphics.Color
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.Utils
import com.android.systemui.res.R
@@ -34,7 +34,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class ActivatableNotificationViewTest : SysuiTestCase() {
private val mContentView: View = mock()
@@ -98,4 +98,4 @@ class ActivatableNotificationViewTest : SysuiTestCase() {
assertThat(mView.topRoundness).isEqualTo(1f)
assertThat(mView.roundableState.hashCode()).isEqualTo(roundableState.hashCode())
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt
index 0eae5fc209b4..fda5cd286074 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt
@@ -20,8 +20,8 @@ import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.net.Uri
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.widget.NotificationDrawableConsumer
import com.android.systemui.SysuiTestCase
@@ -50,7 +50,7 @@ private const val MAX_IMAGE_SIZE = 512 // size of the test drawables in pixels
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWithLooper
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class BigPictureIconManagerTest : SysuiTestCase() {
private val testDispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
index 7dcbd8084594..c5b19ab5862c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
@@ -25,8 +25,8 @@ import android.content.pm.ParceledListSlice
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
@@ -47,7 +47,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ChannelEditorDialogControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index 210b1a7f22f4..e738b616d227 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -21,8 +21,8 @@ import android.app.Notification
import android.net.Uri
import android.os.UserHandle
import android.os.UserHandle.USER_ALL
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.internal.statusbar.IStatusBarService
@@ -71,7 +71,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ExpandableNotificationRowControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
index 9d2f32d77028..1c5f37cc60c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -31,10 +31,10 @@ import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -48,7 +48,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class ExpandableNotificationRowDragControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index aa79c23bdf74..7304bd62293d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -46,13 +46,13 @@ import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.ImageView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
@@ -87,7 +87,7 @@ import java.util.List;
import java.util.function.Consumer;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class ExpandableNotificationRowTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
index ffb8646942b5..d04d6fc5f593 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
@@ -45,13 +45,13 @@ import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
import android.testing.UiThreadTest;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
@@ -72,7 +72,7 @@ import org.mockito.MockitoAnnotations;
import java.util.Locale;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@UiThreadTest
public class FeedbackInfoTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test_package";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
index 5e50af39203f..c325791b1f05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
@@ -20,7 +20,7 @@ import android.app.Flags.FLAG_COMPACT_HEADS_UP_NOTIFICATION
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository
@@ -31,7 +31,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class HeadsUpStyleProviderImplTest : SysuiTestCase() {
@Rule @JvmField val setFlagsRule = SetFlagsRule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
index 25172deb67a7..18fd42da78ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
@@ -22,11 +22,11 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.annotation.NonNull;
import androidx.core.os.CancellationSignal;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -48,7 +48,7 @@ import java.util.ArrayList;
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class NotifBindPipelineTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
index e38adeb0fcd9..29252b27f6d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.notification.row
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -33,7 +33,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class NotifInflationErrorManagerTest : SysuiTestCase() {
private lateinit var manager: NotifInflationErrorManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
index 20cc01accbc3..8b1c95babe38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
@@ -26,9 +26,9 @@ import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
import android.widget.RemoteViews;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -45,7 +45,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class NotifRemoteViewCacheImplTest extends SysuiTestCase {
private NotifRemoteViewCacheImpl mNotifRemoteViewCache;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index 03a84036b4b5..a355cd16ee15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -40,7 +40,6 @@ import android.os.AsyncTask;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.TypedValue;
@@ -49,6 +48,7 @@ import android.view.ViewGroup;
import android.widget.RemoteViews;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.filters.Suppress;
@@ -79,7 +79,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper(setAsMainLooper = true)
@Suppress
public class NotificationContentInflaterTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
index 7332bc34b030..2bb610ac4449 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
@@ -20,7 +20,6 @@ import android.annotation.DimenRes
import android.content.res.Resources
import android.os.UserHandle
import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.ViewUtils
import android.view.NotificationHeaderView
@@ -29,6 +28,7 @@ import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.internal.widget.NotificationActionListLayout
@@ -60,7 +60,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations.initMocks
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class NotificationContentViewTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 97cb11e2f107..be89ab8c5cf8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -65,13 +65,13 @@ import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
@@ -103,7 +103,7 @@ import java.util.Optional;
import java.util.concurrent.CountDownLatch;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class NotificationConversationInfoTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test_package";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 907649b90956..625963f5ec7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -57,12 +57,12 @@ import android.os.Handler;
import android.os.UserManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArraySet;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
@@ -115,7 +115,7 @@ import java.util.Optional;
* Tests for {@link NotificationGutsManager}.
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class NotificationGutsManagerTest extends SysuiTestCase {
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
index 1b85dfa5a087..0b5f8d5e948c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
@@ -31,11 +31,11 @@ import android.os.fakeExecutorHandler
import android.os.userManager
import android.provider.Settings
import android.service.notification.NotificationListenerService.Ranking
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.util.ArraySet
import android.view.View
import android.view.accessibility.accessibilityManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.internal.logging.MetricsLogger
@@ -91,7 +91,7 @@ import org.mockito.invocation.InvocationOnMock
/** Tests for [NotificationGutsManager] with the scene container enabled. */
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
@EnableSceneContainer
class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
index 7f9471e5271f..350f90dcbe91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar.notification.row
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.testing.ViewUtils
import android.view.LayoutInflater
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -34,7 +34,7 @@ import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class NotificationGutsTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 13ced928175e..245a6a0b130c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -55,13 +55,13 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
@@ -85,7 +85,7 @@ import org.mockito.junit.MockitoRule;
import java.util.concurrent.CountDownLatch;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class NotificationInfoTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test_package";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index e9290289f7f2..027e899e20df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -29,13 +29,13 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.ViewUtils;
import android.view.View;
import android.view.ViewGroup;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -49,7 +49,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
@SmallTest
public class NotificationMenuRowTest extends LeakCheckedTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt
index 8261c1c4b42e..352b79f50b90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt
@@ -22,8 +22,8 @@ import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
import android.provider.Settings.Secure
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -54,7 +54,7 @@ import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class NotificationSettingsControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
index 4a91cd239d87..22f1e4604bbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
@@ -23,11 +23,11 @@ import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableResources;
import android.testing.UiThreadTest;
import android.util.KeyValueListParser;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -41,7 +41,7 @@ import org.junit.runner.RunWith;
import java.util.ArrayList;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@UiThreadTest
public class NotificationSnoozeTest extends SysuiTestCase {
private static final int RES_DEFAULT = 2;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index 51665d987888..57b0f3f8d8c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -41,7 +41,6 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.text.SpannableString;
import android.view.LayoutInflater;
@@ -49,6 +48,7 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
@@ -69,7 +69,7 @@ import org.mockito.junit.MockitoRule;
import java.util.concurrent.CountDownLatch;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class PartialConversationInfoTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test_package";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
index 1534c84fd99a..841cb4a3669b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
@@ -34,10 +34,10 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Log;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -52,7 +52,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class RowContentBindStageTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt
index 1c959af6ec3f..53a11989cca0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt
@@ -18,8 +18,8 @@ package com.android.systemui.statusbar.notification.row
import android.app.Notification
import android.app.Person
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.systemui.SysuiTestCase
@@ -34,7 +34,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class SingleLineConversationViewBinderTest : SysuiTestCase() {
private lateinit var notificationBuilder: Notification.Builder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
index f0fc349777b2..ee819c4df0ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
@@ -17,8 +17,8 @@ package com.android.systemui.statusbar.notification.row
import android.app.Notification
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.systemui.SysuiTestCase
@@ -33,7 +33,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class SingleLineViewBinderTest : SysuiTestCase() {
private lateinit var notificationBuilder: Notification.Builder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
index b67153a842ac..e025d3d36ab1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
@@ -27,9 +27,9 @@ import android.graphics.PorterDuffXfermode
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.core.graphics.drawable.toBitmap
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.res.R
@@ -48,7 +48,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@EnableFlags(AsyncHybridViewInflation.FLAG_NAME)
class SingleLineViewInflaterTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/TextPrecomputerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/TextPrecomputerTest.kt
index d46763df8a75..f8533a532d32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/TextPrecomputerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/TextPrecomputerTest.kt
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar.notification.row
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.text.PrecomputedText
import android.text.TextPaint
import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -29,7 +29,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class TextPrecomputerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
index c9602307216d..0dc871a523ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
@@ -18,7 +18,7 @@
package com.android.systemui.statusbar.notification.row.ui.viewmodel
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.accessibility.data.repository.FakeAccessibilityRepository
@@ -31,7 +31,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ActivatableNotificationViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
index a15b4cd37184..ec280a1d6d01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
@@ -24,10 +24,10 @@ import android.app.Notification;
import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
-import android.testing.AndroidTestingRunner;
import android.view.LayoutInflater;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
@@ -40,7 +40,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class NotificationBigPictureTemplateViewWrapperTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
index fe2971c46c32..9d990b1d7edf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.row.wrapper
import android.graphics.drawable.AnimatedImageDrawable
-import android.testing.AndroidTestingRunner
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.internal.widget.CachingIconView
@@ -38,7 +38,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class NotificationConversationTemplateViewWrapperTest : SysuiTestCase() {
private lateinit var mRow: ExpandableNotificationRow
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
index 2d72c7e0b714..f9a9704334a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
@@ -16,10 +16,10 @@
package com.android.systemui.statusbar.notification.row.wrapper;
-import android.testing.AndroidTestingRunner;
import android.view.View;
import android.widget.RemoteViews;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -33,7 +33,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class NotificationCustomViewWrapperTest extends SysuiTestCase {
private ExpandableNotificationRow mRow;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
index f26c18b1d197..fc829d53a6b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.row.wrapper
import android.graphics.drawable.AnimatedImageDrawable
-import android.testing.AndroidTestingRunner
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.widget.MessagingGroup
import com.android.internal.widget.MessagingImageMessage
@@ -36,7 +36,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class NotificationMessagingTemplateViewWrapperTest : SysuiTestCase() {
private lateinit var mRow: ExpandableNotificationRow
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
index 54eed26adaf3..1ce3bada4609 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.row.wrapper
import android.app.PendingIntent
import android.app.PendingIntent.CancelListener
import android.content.Intent
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import android.testing.ViewUtils
@@ -27,6 +26,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.systemui.SysuiTestCase
@@ -46,7 +46,7 @@ import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class NotificationTemplateViewWrapperTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
index fad85f53a091..d17c8dbcf38d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
@@ -20,11 +20,11 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.testing.AndroidTestingRunner;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class NotificationViewWrapperTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
index 59d98c233f99..4c6e25a530a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
@@ -19,7 +19,7 @@
package com.android.systemui.statusbar.notification.shelf.domain.interactor
import android.os.PowerManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -41,7 +41,7 @@ import org.junit.runner.RunWith
import org.mockito.Mockito.isNull
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class NotificationShelfInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
index 917569ca787b..e2fb3ba11a02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
import android.os.PowerManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysUITestComponent
import com.android.systemui.SysUITestModule
@@ -44,7 +44,7 @@ import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class NotificationShelfViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
index fb1594898f24..2349c252369c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.stack
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -33,7 +33,7 @@ import org.junit.runner.RunWith
private const val MAX_PULSE_HEIGHT = 100000f
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class AmbientStateTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
index f4e236e5bbf9..3a77d822eb7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
@@ -1,8 +1,8 @@
package com.android.systemui.statusbar.notification.stack
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.res.R
@@ -15,7 +15,7 @@ import org.junit.runner.RunWith
* Tests for {@link MediaContainView}.
*/
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class MediaContainerViewTest : SysuiTestCase() {
@@ -35,4 +35,4 @@ class MediaContainerViewTest : SysuiTestCase() {
mediaContainerView.updateClipping()
assertTrue(mediaContainerView.clipHeight == 10)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index 3b16f1416935..14bbd38ece2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -21,13 +21,13 @@ import static org.junit.Assert.assertNull;
import android.app.Notification;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.NotificationHeaderView;
import android.view.View;
import android.widget.RemoteViews;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -45,7 +45,7 @@ import org.junit.runner.RunWith;
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
//@DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
public class NotificationChildrenContainerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 1eed4207541c..48e8f88a15c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -2,10 +2,10 @@ package com.android.systemui.statusbar.notification.stack
import android.platform.test.annotations.DisableFlags
import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.LayoutInflater
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
import com.android.systemui.SysuiTestCase
@@ -35,7 +35,7 @@ import org.mockito.Mockito.`when` as whenever
/** Tests for {@link NotificationShelf}. */
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
open class NotificationShelfTest : SysuiTestCase() {
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 f262df1d875a..ce2491bb098e 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
@@ -42,12 +42,12 @@ import static org.mockito.Mockito.when;
import android.metrics.LogMaker;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
@@ -126,7 +126,7 @@ import javax.inject.Provider;
*/
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
protected KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 0c0a2a59d9bc..f461e2f67d20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -54,7 +54,6 @@ import android.graphics.Rect;
import android.os.SystemClock;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableResources;
import android.util.MathUtils;
@@ -65,6 +64,7 @@ import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.keyguard.BouncerPanelExpansionCalculator;
@@ -114,7 +114,7 @@ import java.util.function.Consumer;
* Tests for {@link NotificationStackScrollLayout}.
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class NotificationStackScrollLayoutTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
index 6fec9ad7bd66..dae5542123ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
@@ -18,8 +18,8 @@ package com.android.systemui.statusbar.notification.stack
import android.annotation.DimenRes
import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
import android.view.View.VISIBLE
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -44,7 +44,7 @@ import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class NotificationStackSizeCalculatorTest : SysuiTestCase() {
@Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 85a2bdd21073..2d119174efff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -37,12 +37,12 @@ import android.animation.Animator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.os.Handler;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -70,7 +70,7 @@ import java.util.stream.Collectors;
* Tests for {@link NotificationSwipeHelper}.
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper()
public class NotificationSwipeHelperTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
index e30947ce84bd..660eb308fdf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
@@ -1,8 +1,8 @@
package com.android.systemui.statusbar.notification.stack
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FakeFeatureFlags
@@ -15,7 +15,7 @@ import org.junit.runner.RunWith
/** Tests for {@link NotificationTargetsHelper}. */
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class NotificationTargetsHelperTest : SysuiTestCase() {
private val featureFlags = FakeFeatureFlags()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
index 926c35f32967..798465e7b165 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.stack
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.AnimatorTestRule
@@ -48,7 +48,7 @@ private const val FULL_SHADE_APPEAR_TRANSLATION = 300
private const val HEADS_UP_ABOVE_SCREEN = 80
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class StackStateAnimatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
index cd6bb5f4966a..e493420b64a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.stack
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.assertDoesNotLogWtf
@@ -27,7 +27,7 @@ import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ViewStateTest : SysuiTestCase() {
private val viewState = ViewState()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
index e2ac2038be32..e46906fb5192 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
@@ -17,10 +17,10 @@ package com.android.systemui.statusbar.notification.stack.domain.interactor
import android.content.res.Configuration
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.view.Surface
import android.view.Surface.ROTATION_0
import android.view.Surface.ROTATION_90
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImpl
@@ -52,7 +52,7 @@ import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
open class HideNotificationsInteractorTest : SysuiTestCase() {
private val testScope = TestScope()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 84cd518cf85a..f0bc655a554d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -45,10 +45,10 @@ import android.hardware.display.ColorDisplayManager;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -89,7 +89,7 @@ import java.util.List;
import javax.inject.Named;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
@SmallTest
public class AutoTileManagerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index dc7525c8e256..285949a41fcd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -37,11 +37,11 @@ import android.hardware.biometrics.BiometricSourceType;
import android.os.Handler;
import android.os.PowerManager;
import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.TestableResources;
import android.view.ViewRootImpl;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
@@ -77,7 +77,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class BiometricsUnlockControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index fe6a88d00374..5675915506a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -30,9 +30,9 @@ import android.content.ComponentName;
import android.os.PowerManager;
import android.os.UserHandle;
import android.os.Vibrator;
-import android.testing.AndroidTestingRunner;
import android.view.HapticFeedbackConstants;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
@@ -71,7 +71,7 @@ import org.mockito.stubbing.Answer;
import java.util.Optional;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase {
@Mock private CentralSurfaces mCentralSurfaces;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 4488799cfd7a..cde241bbe918 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -57,6 +57,7 @@ import android.app.WallpaperManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceState;
@@ -75,7 +76,6 @@ import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.service.dreams.IDreamManager;
import android.support.test.metricshelper.MetricsAsserts;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.DisplayMetrics;
@@ -85,6 +85,7 @@ import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.WindowMetrics;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.compose.animation.scene.ObservableTransitionState;
@@ -223,7 +224,7 @@ import java.util.Optional;
import javax.inject.Provider;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper(setAsMainLooper = true)
@EnableFlags(FLAG_LIGHT_REVEAL_MIGRATION)
public class CentralSurfacesImplTest extends SysuiTestCase {
@@ -339,6 +340,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
@Mock private WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
@Mock private KeyboardShortcuts mKeyboardShortcuts;
@Mock private KeyboardShortcutListSearch mKeyboardShortcutListSearch;
+ @Mock private PackageManager mPackageManager;
private ShadeController mShadeController;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
@@ -392,7 +394,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mock(UiEventLogger.class),
mUserTracker,
mAvalancheProvider,
- mSystemSettings);
+ mSystemSettings,
+ mPackageManager);
mVisualInterruptionDecisionProvider.start();
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
index 56d23978a5c7..942ea65ec49e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
@@ -21,7 +21,7 @@ import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.content.res.Configuration.UI_MODE_TYPE_CAR
import android.os.LocaleList
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
@@ -36,7 +36,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import java.util.Locale
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ConfigurationControllerImplTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
index 34c43ef52a00..3b3ec263145a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
@@ -20,9 +20,9 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -36,7 +36,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@SmallTest
public class DozeScrimControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
index 5d42d5167c27..a3e2d1949a29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.phone
import android.hardware.devicestate.DeviceState
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.systemui.SysuiTestCase
@@ -30,7 +30,7 @@ import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations.initMocks
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FoldStateListenerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 3e9006e5268c..0d06b6431e1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -26,12 +26,12 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -62,7 +62,7 @@ import org.junit.runner.RunWith;
import java.util.Optional;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index e8346933f192..cf87afbbff34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -28,8 +28,8 @@ import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
@@ -50,7 +50,7 @@ import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
private static final int SCREEN_HEIGHT = 2000;
private static final int EMPTY_HEIGHT = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
index b0aa2d3934cc..d880becaa4bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
@@ -20,8 +20,8 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class KeyguardDismissUtilTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
index 5cea931e2070..109cd948b5b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
@@ -21,10 +21,10 @@ import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE;
import static com.google.common.truth.Truth.assertThat;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class KeyguardIndicationTextViewTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 5b2526e22679..71f09a5d3f04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -42,11 +42,11 @@ import android.os.UserManager;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.keyguard.CarrierTextController;
@@ -99,7 +99,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
index c44f979fa971..0932a0c9307c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
@@ -18,11 +18,11 @@ package com.android.systemui.statusbar.phone;
import static com.google.common.truth.Truth.assertThat;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -33,7 +33,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class KeyguardStatusBarViewTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
index f91064b49e95..782ca91bc8fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
import android.view.View;
@@ -35,6 +34,7 @@ import android.view.WindowInsets;
import android.view.WindowManager;
import androidx.lifecycle.Observer;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -54,7 +54,7 @@ import org.mockito.MockitoAnnotations;
import java.util.Objects;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
@DisableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
public class LegacyLightsOutNotifControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
index 9d53b9c66b33..fea0e72fe577 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
@@ -21,9 +21,9 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
@@ -49,7 +49,7 @@ import org.mockito.MockitoAnnotations;
import java.util.Optional;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@DisableFlags(NotificationIconContainerRefactor.FLAG_NAME)
public class LegacyNotificationIconAreaControllerImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
index e7b287c5bdc8..518b327036cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
@@ -18,9 +18,9 @@ package com.android.systemui.statusbar.phone
import android.graphics.Color
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.view.WindowInsetsController
import android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.statusbar.LetterboxDetails
import com.android.internal.view.AppearanceRegion
@@ -36,7 +36,7 @@ import org.mockito.Mock
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class LetterboxAppearanceCalculatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
index 1cc0bd3cb36c..788c2cb2a485 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
@@ -21,8 +21,8 @@ import android.app.WallpaperManager.OnColorsChangedListener
import android.graphics.Color
import android.os.Handler
import android.os.Looper
-import android.testing.AndroidTestingRunner
import android.view.IWindowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -40,7 +40,7 @@ import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class LetterboxBackgroundProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
index 7271a5efc377..a27073c77eb4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
@@ -35,10 +35,10 @@ import static org.mockito.Mockito.when;
import android.graphics.Color;
import android.graphics.Rect;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.annotation.ColorInt;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
@@ -67,7 +67,7 @@ import java.util.Arrays;
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class LightBarControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
index f71114d92aa3..43c19b833646 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
@@ -28,9 +28,9 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.policy.GestureNavigationSettingsObserver;
@@ -48,7 +48,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class LightBarTransitionsControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
index 9f4e1dd8cc4d..9d97e5a5686e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.phone
import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.StatusBarIconView
@@ -34,7 +34,7 @@ import org.mockito.Mockito.`when` as whenever
/** Tests for {@link NotificationIconContainer}. */
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class NotificationIconContainerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
index ccd1a8c7a9b2..9522e1f65a4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
@@ -22,11 +22,11 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.Resources;
-import android.testing.AndroidTestingRunner;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -42,7 +42,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class NotificationTapHelperTest extends SysuiTestCase {
private NotificationTapHelper mNotificationTapHelper;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
index 8d2c1588fb62..f2f336c45d7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -22,9 +22,9 @@ import android.app.admin.DevicePolicyResourcesManager
import android.content.SharedPreferences
import android.os.UserManager
import android.telecom.TelecomManager
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -79,7 +79,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 1000329cb276..416a869bf2f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -49,12 +49,12 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.ViewUtils;
import android.util.MathUtils;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
@@ -107,7 +107,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class ScrimControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt
index 61da701ce971..b9cfe21dcad3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt
@@ -17,10 +17,10 @@
package com.android.systemui.statusbar.phone
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.View
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.phone.StatusBarBoundsProvider.BoundsChangeListener
@@ -37,7 +37,7 @@ import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
class StatusBarBoundsProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 6b3c0053e738..3ca4c594cede 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -41,7 +41,6 @@ import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.service.trust.TrustAgentService;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
import android.view.View;
@@ -55,6 +54,7 @@ import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import android.window.WindowOnBackInvokedDispatcher;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.util.LatencyTracker;
@@ -119,7 +119,7 @@ import org.mockito.MockitoAnnotations;
import java.util.Optional;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 269510e0b4b2..9fa392f3a337 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -51,9 +51,9 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.jank.InteractionJankMonitor;
@@ -119,7 +119,7 @@ import java.util.List;
import java.util.Optional;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index a8c5fc357c7c..95472cad4b90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -34,10 +34,10 @@ import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.InitController;
@@ -85,7 +85,7 @@ import java.util.List;
import java.util.Set;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper()
public class StatusBarNotificationPresenterTest extends SysuiTestCase {
private StatusBarNotificationPresenter mStatusBarNotificationPresenter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 929099a8f1f7..35888a5fa734 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -24,10 +24,10 @@ import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import android.content.Intent;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -52,7 +52,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@@ -103,4 +103,4 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
verify(mStatusBarKeyguardViewManager).showBouncer(true);
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
index 1455693fc54b..11dd587a04ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
@@ -21,7 +21,6 @@ import android.graphics.Color
import android.graphics.drawable.Drawable
import android.graphics.drawable.PaintDrawable
import android.os.SystemClock
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import android.testing.ViewUtils
@@ -30,6 +29,7 @@ import android.view.View
import android.view.ViewGroupOverlay
import android.widget.LinearLayout
import androidx.annotation.ColorInt
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -45,7 +45,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
class StatusOverlayHoverListenerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
index dedd0afb6127..b560c591af1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
@@ -15,9 +15,9 @@ package com.android.systemui.statusbar.phone
import android.app.Dialog
import android.content.res.Configuration
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.WindowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
@@ -39,7 +39,7 @@ import org.mockito.Mockito.verify
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
class SystemUIBottomSheetDialogTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
index c8ff20b31aae..624c070e95e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -18,9 +18,9 @@ package com.android.systemui.statusbar.phone
import android.os.Handler
import android.os.PowerManager
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.SysuiTestCase
@@ -51,7 +51,7 @@ import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 66211c922abb..fdf77ae87011 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -426,7 +426,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
}
@Test
@@ -438,7 +438,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
@@ -452,7 +452,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
}
@Test
@@ -465,7 +465,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
}
@Test
@@ -477,21 +477,21 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
// Ongoing call ended
when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
// Ongoing call started
when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index 05464f3b715a..4d6798be9211 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -106,7 +106,7 @@ class OngoingCallControllerTest : SysuiTestCase() {
fun setUp() {
allowTestableLooperAsMainThread()
TestableLooper.get(this).runWithLooper {
- chipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_call_chip, null)
+ chipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip, null)
}
MockitoAnnotations.initMocks(this)
@@ -206,7 +206,7 @@ class OngoingCallControllerTest : SysuiTestCase() {
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
- assertThat(chipView.findViewById<View>(R.id.ongoing_call_chip_time)?.measuredWidth)
+ assertThat(chipView.findViewById<View>(R.id.ongoing_activity_chip_time)?.measuredWidth)
.isEqualTo(0)
}
@@ -222,7 +222,7 @@ class OngoingCallControllerTest : SysuiTestCase() {
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
- assertThat(chipView.findViewById<View>(R.id.ongoing_call_chip_time)?.measuredWidth)
+ assertThat(chipView.findViewById<View>(R.id.ongoing_activity_chip_time)?.measuredWidth)
.isGreaterThan(0)
}
@@ -237,7 +237,7 @@ class OngoingCallControllerTest : SysuiTestCase() {
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
- assertThat(chipView.findViewById<View>(R.id.ongoing_call_chip_time)?.measuredWidth)
+ assertThat(chipView.findViewById<View>(R.id.ongoing_activity_chip_time)?.measuredWidth)
.isGreaterThan(0)
}
@@ -472,7 +472,10 @@ class OngoingCallControllerTest : SysuiTestCase() {
lateinit var newChipView: View
TestableLooper.get(this).runWithLooper {
- newChipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_call_chip, null)
+ newChipView = LayoutInflater.from(mContext).inflate(
+ R.layout.ongoing_activity_chip,
+ null
+ )
}
// Change the chip view associated with the controller.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 598b12ccdc38..eb2538ec032e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -20,6 +20,7 @@ import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import android.telephony.TelephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.demomode.DemoMode
@@ -60,7 +61,6 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -73,7 +73,7 @@ import org.mockito.MockitoAnnotations
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class MobileRepositorySwitcherTest : SysuiTestCase() {
private lateinit var underTest: MobileRepositorySwitcher
private lateinit var realRepo: MobileConnectionsRepositoryImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
index 265440154d77..237aabccfbd9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
import android.telephony.TelephonyManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -44,7 +44,7 @@ import org.mockito.MockitoAnnotations
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
private lateinit var underTest: CarrierMergedConnectionRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 36df61d287a1..96e599f8f4d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+import android.annotation.SuppressLint
import android.content.Intent
import android.net.ConnectivityManager
import android.net.Network
@@ -27,8 +28,10 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.vcn.VcnTransportInfo
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
+import android.os.Bundle
import android.os.ParcelUuid
import android.telephony.CarrierConfigManager
+import android.telephony.ServiceState
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
@@ -53,6 +56,7 @@ import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
@@ -595,6 +599,51 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
}
+ @SuppressLint("UnspecifiedRegisterReceiverFlag")
+ @Test
+ fun testDeviceServiceStateFromBroadcast_eagerlyWatchesBroadcast() =
+ testScope.runTest {
+ // Value starts out empty (null)
+ assertThat(underTest.deviceServiceState.value).isNull()
+
+ // WHEN an appropriate intent gets sent out
+ val intent = serviceStateIntent(subId = -1, emergencyOnly = false)
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ intent,
+ )
+ runCurrent()
+
+ // THEN the repo's state is updated
+ val expected = ServiceStateModel(isEmergencyOnly = false)
+ assertThat(underTest.deviceServiceState.value).isEqualTo(expected)
+ }
+
+ @Test
+ fun testDeviceServiceStateFromBroadcast_followsSubIdNegativeOne() =
+ testScope.runTest {
+ // device based state tracks -1
+ val intent = serviceStateIntent(subId = -1, emergencyOnly = false)
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ intent,
+ )
+ runCurrent()
+
+ val deviceBasedState = ServiceStateModel(isEmergencyOnly = false)
+ assertThat(underTest.deviceServiceState.value).isEqualTo(deviceBasedState)
+
+ // ... and ignores any other subId
+ val intent2 = serviceStateIntent(subId = 1, emergencyOnly = true)
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ intent2,
+ )
+ runCurrent()
+
+ assertThat(underTest.deviceServiceState.value).isEqualTo(deviceBasedState)
+ }
+
@Test
@Ignore("b/333912012")
fun testConnectionCache_clearsInvalidSubscriptions() =
@@ -1491,5 +1540,24 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
whenever(it.transportInfo).thenReturn(WIFI_INFO_ACTIVE)
whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(true)
}
+
+ /**
+ * To properly mimic telephony manager, create a service state, and then turn it into an
+ * intent
+ */
+ private fun serviceStateIntent(
+ subId: Int,
+ emergencyOnly: Boolean = false,
+ ): Intent {
+ val serviceState = ServiceState().apply { isEmergencyOnly = emergencyOnly }
+
+ val bundle = Bundle()
+ serviceState.fillInNotifierBundle(bundle)
+
+ return Intent(Intent.ACTION_SERVICE_STATE).apply {
+ putExtras(bundle)
+ putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId)
+ }
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 0f9cbfa66b5b..58d9ee3935fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -28,6 +28,7 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
@@ -888,6 +889,22 @@ class MobileIconsInteractorTest : SysuiTestCase() {
assertThat(interactor1).isSameInstanceAs(interactor2)
}
+ @Test
+ fun deviceBasedEmergencyMode_emergencyCallsOnly_followsDeviceServiceStateFromRepo() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isDeviceInEmergencyCallsOnlyMode)
+
+ connectionsRepository.deviceServiceState.value =
+ ServiceStateModel(isEmergencyOnly = true)
+
+ assertThat(latest).isTrue()
+
+ connectionsRepository.deviceServiceState.value =
+ ServiceStateModel(isEmergencyOnly = false)
+
+ assertThat(latest).isFalse()
+ }
+
/**
* Convenience method for creating a pair of subscriptions to test the filteredSubscriptions
* flow.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
index 405e3ed807d5..d303976612c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
@@ -22,6 +22,7 @@ import androidx.test.filters.SmallTest
import com.android.internal.telephony.flags.Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.log.core.FakeLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.satellite.data.prod.FakeDeviceBasedSatelliteRepository
@@ -71,6 +72,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() {
deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
+ FakeLogBuffer.Factory.create(),
)
}
@@ -114,6 +116,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() {
deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
+ FakeLogBuffer.Factory.create(),
)
val latest by collectLastValue(underTest.isSatelliteAllowed)
@@ -162,6 +165,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() {
deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
+ FakeLogBuffer.Factory.create(),
)
val latest by collectLastValue(underTest.connectionState)
@@ -218,6 +222,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() {
deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
+ FakeLogBuffer.Factory.create(),
)
val latest by collectLastValue(underTest.signalStrength)
@@ -238,25 +243,97 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
- fun areAllConnectionsOutOfService_noConnections_yes() =
+ fun areAllConnectionsOutOfService_noConnections_noDeviceEmergencyCalls_yes() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
// GIVEN, 0 connections
+ // GIVEN, device is not in emergency calls only mode
+ iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = false
+
// THEN the value is propagated to this interactor
assertThat(latest).isTrue()
}
@Test
@EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
- fun areAllConnectionsOutOfService_twoConnectionsOos_nonNtn_yes() =
+ fun areAllConnectionsOutOfService_noConnections_deviceEmergencyCalls_yes() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+ // GIVEN, 0 connections
+
+ // GIVEN, device is in emergency calls only mode
+ iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = true
+
+ // THEN the value is propagated to this interactor
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun areAllConnectionsOutOfService_oneConnectionInService_thenLost_noDeviceEmergencyCalls_yes() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+ // GIVEN, 1 connections
+ val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+ // GIVEN, no device-based emergency calls
+ iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = false
+
+ // WHEN connection is in service
+ i1.isInService.value = true
+ i1.isEmergencyOnly.value = false
+ i1.isNonTerrestrial.value = false
+
+ // THEN we are considered NOT to be OOS
+ assertThat(latest).isFalse()
+
+ // WHEN the connection disappears
+ iconsInteractor.icons.value = listOf()
+
+ // THEN we are back to OOS
+ assertThat(latest).isTrue()
+ }
+
+ @Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun areAllConnectionsOutOfService_oneConnectionInService_thenLost_deviceEmergencyCalls_no() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+ // GIVEN, 1 connections
+ val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+ // GIVEN, device-based emergency calls
+ iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = true
+
+ // WHEN one connection is in service
+ i1.isInService.value = true
+ i1.isEmergencyOnly.value = false
+ i1.isNonTerrestrial.value = false
+
+ // THEN we are considered NOT to be OOS
+ assertThat(latest).isFalse()
+
+ // WHEN the connection disappears
+ iconsInteractor.icons.value = listOf()
+
+ // THEN we are still NOT in OOS, due to device-based emergency calls
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun areAllConnectionsOutOfService_twoConnectionsOos_nonNtn_noDeviceEmergencyCalls_yes() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
// GIVEN, 2 connections
val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2)
+ // GIVEN, no device-based emergency calls
+ iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = false
// WHEN all of the connections are OOS and none are NTN
i1.isInService.value = false
@@ -272,13 +349,39 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
- fun areAllConnectionsOutOfService_twoConnectionsOos_oneNtn_no() =
+ fun areAllConnectionsOutOfService_twoConnectionsOos_nonNtn_deviceEmergencyCalls_no() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+ // GIVEN, 2 connections
+ val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+ val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2)
+ // GIVEN, device-based emergency calls
+ iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = true
+
+ // WHEN all of the connections are OOS and none are NTN
+ i1.isInService.value = false
+ i1.isEmergencyOnly.value = false
+ i1.isNonTerrestrial.value = false
+ i2.isInService.value = false
+ i2.isEmergencyOnly.value = false
+ i2.isNonTerrestrial.value = false
+
+ // THEN we are not considered OOS due to device based emergency calling
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun areAllConnectionsOutOfService_twoConnectionsOos_noDeviceEmergencyCalls_oneNtn_no() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
// GIVEN, 2 connections
val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2)
+ // GIVEN, no device-based emergency calls
+ iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = false
// WHEN all of the connections are OOS and one is NTN
i1.isInService.value = false
@@ -296,12 +399,14 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
- fun areAllConnectionsOutOfService_oneConnectionOos_nonNtn_yes() =
+ fun areAllConnectionsOutOfService_oneConnectionOos_noDeviceEmergencyCalls_nonNtn_yes() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
// GIVEN, 1 connection
val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+ // GIVEN, no device-based emergency calls
+ iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = false
// WHEN all of the connections are OOS
i1.isInService.value = false
@@ -314,7 +419,27 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
- fun areAllConnectionsOutOfService_oneConnectionOos_ntn_yes() =
+ fun areAllConnectionsOutOfService_oneConnectionOos_nonNtn_no() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+ // GIVEN, 1 connection
+ val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+ // GIVEN, device-based emergency calls
+ iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = true
+
+ // WHEN all of the connections are OOS
+ i1.isInService.value = false
+ i1.isEmergencyOnly.value = false
+ i1.isNonTerrestrial.value = false
+
+ // THEN the value is propagated to this interactor
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun areAllConnectionsOutOfService_oneConnectionOos_ntn_no() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -416,6 +541,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() {
deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
+ FakeLogBuffer.Factory.create(),
)
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
index ceaae9e02e87..43b95688729c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
@@ -75,6 +75,7 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() {
deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
+ FakeLogBuffer.Factory.create(),
)
underTest =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
index d1c38f6cbea7..0a5e63085b9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
@@ -22,6 +22,7 @@ import android.graphics.Bitmap
import android.os.UserHandle
import android.view.View
import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.qs.user.UserSwitchDialogController
@@ -33,14 +34,13 @@ import java.lang.ref.WeakReference
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class BaseUserSwitcherAdapterTest : SysuiTestCase() {
@Mock private lateinit var controller: UserSwitcherController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
index fb4ccb52929a..c22c62825d04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
@@ -20,8 +20,8 @@ import android.content.ComponentName
import android.content.Context
import android.content.pm.ServiceInfo
import android.provider.Settings
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
@@ -60,7 +60,7 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyObject
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class DeviceControlsControllerImplTest : SysuiTestCase() {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index 2955162f80c2..f6e07d3d621e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -29,10 +29,10 @@ import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.os.UserHandle;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableContentResolver;
import android.testing.TestableResources;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
@@ -51,7 +51,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt
index 1c54263cb0ce..80cc6eca8405 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt
@@ -20,8 +20,8 @@ import android.content.pm.PackageManager
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import android.hardware.camera2.impl.CameraMetadataNative
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dump.DumpManager
@@ -46,7 +46,7 @@ import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class FlashlightControllerImplTest : SysuiTestCase() {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
index 0bd6a685708b..9f74915b4d1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
@@ -19,10 +19,10 @@ package com.android.systemui.statusbar.policy
import android.content.Context
import android.content.pm.UserInfo
import android.graphics.Bitmap
-import android.testing.AndroidTestingRunner
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.util.UserIcons
import com.android.systemui.res.R
@@ -44,7 +44,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class KeyguardUserSwitcherAdapterTest : SysuiTestCase() {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
index b03edaf8ebd5..4b14e642063a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
@@ -23,7 +23,7 @@ import android.content.pm.PackageManager
import android.net.Uri
import android.os.Handler
import android.safetycenter.SafetyCenterManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
@@ -44,7 +44,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class SafetyControllerTest : SysuiTestCase() {
private val TEST_PC_PKG = "testPermissionControllerPackageName"
@@ -188,4 +188,4 @@ class SafetyControllerTest : SysuiTestCase() {
assertThat(called).isTrue()
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
index 3e20f689569e..81f095041fbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
@@ -22,7 +22,7 @@ import android.media.projection.MediaProjectionManager
import android.os.Handler
import android.platform.test.annotations.DisableFlags
import android.telephony.TelephonyManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.server.notification.Flags
import com.android.systemui.SysuiTestCase
@@ -38,7 +38,7 @@ import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@DisableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING)
class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase() {
private val logger = SensitiveNotificationProtectionControllerLogger(logcatLogBuffer())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
index dbc2e3471c28..0249ab8fc9eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.policy
import android.service.quickaccesswallet.QuickAccessWalletClient
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -35,7 +35,7 @@ import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when`
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class WalletControllerImplTest : SysuiTestCase() {
@Mock
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 aac36405e9b6..daea7b94ac4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -27,6 +27,7 @@ import static android.service.notification.NotificationListenerService.REASON_GR
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING;
+import static com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_BAR;
import static com.google.common.truth.Truth.assertThat;
@@ -466,7 +467,8 @@ public class BubblesTest extends SysuiTestCase {
mock(UiEventLogger.class),
mock(UserTracker.class),
mock(AvalancheProvider.class),
- mock(SystemSettings.class)
+ mock(SystemSettings.class),
+ mock(PackageManager.class)
);
interruptionDecisionProvider.start();
@@ -2141,6 +2143,112 @@ public class BubblesTest extends SysuiTestCase {
assertThat(mBubbleController.getLayerView().isExpanded()).isFalse();
}
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @Test
+ public void dragBubbleBarBubble_selectedBubble_expandedViewCollapsesDuringDrag() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ // Add 2 bubbles
+ mEntryListener.onEntryAdded(mRow);
+ mEntryListener.onEntryAdded(mRow2);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
+
+ // Select first bubble
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+ assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
+ assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
+
+ // Drag first bubble, bubble should collapse
+ mBubbleController.startBubbleDrag(mBubbleEntry.getKey());
+ assertThat(mBubbleController.getLayerView().isExpanded()).isFalse();
+
+ // Stop dragging, first bubble should be expanded
+ mBubbleController.stopBubbleDrag(BubbleBarLocation.LEFT);
+ assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
+ assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
+ }
+
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @Test
+ public void dragBubbleBarBubble_unselectedBubble_expandedViewCollapsesDuringDrag() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ // Add 2 bubbles
+ mEntryListener.onEntryAdded(mRow);
+ mEntryListener.onEntryAdded(mRow2);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
+
+ // Select first bubble
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+ assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
+ assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
+
+ // Drag second bubble, bubble should collapse
+ mBubbleController.startBubbleDrag(mBubbleEntry2.getKey());
+ assertThat(mBubbleController.getLayerView().isExpanded()).isFalse();
+
+ // Stop dragging, first bubble should be expanded
+ mBubbleController.stopBubbleDrag(BubbleBarLocation.LEFT);
+ assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
+ assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
+ }
+
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @Test
+ public void dismissBubbleBarBubble_selected_selectsAndExpandsNext() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ // Add 2 bubbles
+ mEntryListener.onEntryAdded(mRow);
+ mEntryListener.onEntryAdded(mRow2);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
+
+ // Select first bubble
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+ // Drag first bubble to dismiss
+ mBubbleController.startBubbleDrag(mBubbleEntry.getKey());
+ mBubbleController.dragBubbleToDismiss(mBubbleEntry.getKey());
+ // Second bubble is selected and expanded
+ assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry2.getKey());
+ assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
+ }
+
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @Test
+ public void dismissBubbleBarBubble_unselected_selectionDoesNotChange() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ // Add 2 bubbles
+ mEntryListener.onEntryAdded(mRow);
+ mEntryListener.onEntryAdded(mRow2);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
+
+ // Select first bubble
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+ // Drag second bubble to dismiss
+ mBubbleController.startBubbleDrag(mBubbleEntry2.getKey());
+ mBubbleController.dragBubbleToDismiss(mBubbleEntry2.getKey());
+ // First bubble remains selected and expanded
+ assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
+ assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
+ }
+
@DisableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING)
@Test
public void doesNotRegisterSensitiveStateListener() {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 9dcd94687668..8eef930cbb0c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui;
-import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
-
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -99,8 +97,22 @@ public abstract class SysuiTestCase {
.setProvideMainThread(true)
.build();
- @Rule
- public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+ @ClassRule
+ public static final SetFlagsRule.ClassRule mSetFlagsClassRule =
+ new SetFlagsRule.ClassRule(
+ android.app.Flags.class,
+ android.hardware.biometrics.Flags.class,
+ android.multiuser.Flags.class,
+ android.net.platform.flags.Flags.class,
+ android.os.Flags.class,
+ android.service.controls.flags.Flags.class,
+ com.android.internal.telephony.flags.Flags.class,
+ com.android.server.notification.Flags.class,
+ com.android.systemui.Flags.class);
+
+ // TODO(b/339471826): Fix Robolectric to execute the @ClassRule correctly
+ @Rule public final SetFlagsRule mSetFlagsRule =
+ isRobolectricTest() ? new SetFlagsRule() : mSetFlagsClassRule.createSetFlagsRule();
@Rule(order = 10)
public final SceneContainerRule mSceneContainerRule = new SceneContainerRule();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeBrightnessPolicyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeBrightnessPolicyRepository.kt
index d3ceb15ca5a2..f5d02f328336 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeBrightnessPolicyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeBrightnessPolicyRepository.kt
@@ -38,4 +38,8 @@ class FakeBrightnessPolicyRepository : BrightnessPolicyRepository {
)
)
}
+
+ fun setBaseUserRestriction() {
+ _restrictionPolicy.value = PolicyRestriction.Restricted(RestrictedLockUtils.EnforcedAdmin())
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qrcodescanner/QRCodeScannerControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qrcodescanner/QRCodeScannerControllerKosmos.kt
new file mode 100644
index 000000000000..8ad6087cfe82
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qrcodescanner/QRCodeScannerControllerKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.qrcodescanner
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
+import com.android.systemui.util.mockito.mock
+
+val Kosmos.qrCodeScannerController by Kosmos.Fixture { mock<QRCodeScannerController>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt
index c4bf8ff12817..f50443ec4e86 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt
@@ -31,7 +31,11 @@ class FakeQSTileIntentUserInputHandler : QSTileIntentUserInputHandler {
private val mutableInputs = mutableListOf<Input>()
- override fun handle(expandable: Expandable?, intent: Intent) {
+ override fun handle(
+ expandable: Expandable?,
+ intent: Intent,
+ handleDismissShadeShowOverLockScreenWhenLocked: Boolean
+ ) {
mutableInputs.add(Input.Intent(expandable, intent))
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerKosmos.kt
new file mode 100644
index 000000000000..ccfb6092a2e3
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerKosmos.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.actions
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.qsTileIntentUserInputHandler by Kosmos.Fixture { FakeQSTileIntentUserInputHandler() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsKosmos.kt
new file mode 100644
index 000000000000..146c1ad6ab70
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.analytics
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+val Kosmos.qsTileAnalytics by Kosmos.Fixture { mock<QSTileAnalytics>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorKosmos.kt
new file mode 100644
index 000000000000..9ad49f052c9e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorKosmos.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.interactor
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeDisabledByPolicyInteractor by Kosmos.Fixture { FakeDisabledByPolicyInteractor() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt
new file mode 100644
index 000000000000..dcfcce77942e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.qr
+
+import android.content.res.mainResources
+import com.android.systemui.classifier.fakeFalsingManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.backgroundCoroutineContext
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.qrcodescanner.dagger.QRCodeScannerModule
+import com.android.systemui.qrcodescanner.qrCodeScannerController
+import com.android.systemui.qs.qsEventLogger
+import com.android.systemui.qs.tiles.base.actions.qsTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.analytics.qsTileAnalytics
+import com.android.systemui.qs.tiles.base.interactor.fakeDisabledByPolicyInteractor
+import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelImpl
+import com.android.systemui.qs.tiles.impl.custom.qsTileLogger
+import com.android.systemui.qs.tiles.impl.qr.domain.interactor.QRCodeScannerTileDataInteractor
+import com.android.systemui.qs.tiles.impl.qr.domain.interactor.QRCodeScannerTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.qr.ui.QRCodeScannerTileMapper
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.android.systemui.util.time.systemClock
+
+val Kosmos.qsQRCodeScannerTileConfig by
+ Kosmos.Fixture { QRCodeScannerModule.provideQRCodeScannerTileConfig(qsEventLogger) }
+
+val Kosmos.qrCodeScannerTileDataInteractor by
+ Kosmos.Fixture {
+ QRCodeScannerTileDataInteractor(
+ backgroundCoroutineContext,
+ applicationCoroutineScope,
+ qrCodeScannerController
+ )
+ }
+
+val Kosmos.qrCodeScannerTileUserActionInteractor by
+ Kosmos.Fixture { QRCodeScannerTileUserActionInteractor(qsTileIntentUserInputHandler) }
+
+val Kosmos.qrCodeScannerTileMapper by
+ Kosmos.Fixture { QRCodeScannerTileMapper(mainResources, mainResources.newTheme()) }
+
+val Kosmos.qsQRCodeScannerViewModel by
+ Kosmos.Fixture {
+ QSTileViewModelImpl(
+ qsQRCodeScannerTileConfig,
+ { qrCodeScannerTileUserActionInteractor },
+ { qrCodeScannerTileDataInteractor },
+ { qrCodeScannerTileMapper },
+ fakeDisabledByPolicyInteractor,
+ fakeUserRepository,
+ fakeFalsingManager,
+ qsTileAnalytics,
+ qsTileLogger,
+ systemClock,
+ testDispatcher,
+ testScope.backgroundScope,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index cce038f4ffc1..8229575a128f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -23,6 +23,7 @@ import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
@@ -93,6 +94,8 @@ class FakeMobileConnectionsRepository(
private val _defaultMobileIconGroup = MutableStateFlow(DEFAULT_ICON)
override val defaultMobileIconGroup = _defaultMobileIconGroup
+ override val deviceServiceState = MutableStateFlow<ServiceStateModel?>(null)
+
override val isAnySimSecure = MutableStateFlow(false)
override fun getIsAnySimSecure(): Boolean = isAnySimSecure.value
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index de6c87c2b515..3a4bf8e48d33 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -81,6 +81,8 @@ class FakeMobileIconsInteractor(
override val isForceHidden = MutableStateFlow(false)
+ override val isDeviceInEmergencyCallsOnlyMode = MutableStateFlow(false)
+
/** Always returns a new fake interactor */
override fun getMobileConnectionInteractorForSubId(subId: Int): FakeMobileIconInteractor {
return FakeMobileIconInteractor(tableLogBuffer).also {
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 2b18b7d1cff2..a50fb9a4c318 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -138,6 +138,16 @@ flag {
}
flag {
+ name: "manager_package_monitor_logic_fix"
+ namespace: "accessibility"
+ description: "Corrects the return values of the HandleForceStop function"
+ bug: "337392123"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "pinch_zoom_zero_min_span"
namespace: "accessibility"
description: "Whether to set min span of ScaleGestureDetector to zero."
@@ -152,6 +162,16 @@ flag {
}
flag {
+ name: "remove_on_window_infos_changed_handler"
+ namespace: "accessibility"
+ description: "Updates onWindowInfosChanged() to run without posting to a handler."
+ bug: "333834990"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "reset_hover_event_timer_on_action_up"
namespace: "accessibility"
description: "Reset the timer for sending hover events on receiving ACTION_UP to guarantee the correct amount of time is available between taps."
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c70b6419e3b8..a15d2ca57788 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -697,7 +697,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
/**
* Returns the lock object for any synchronized test blocks.
- * Should not be used outside of testing.
+ * External classes should only use for testing.
* @return lock object.
*/
@VisibleForTesting
@@ -801,7 +801,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*
* @param packages list of packages that have stopped.
* @param userState user state to be read & modified.
- * @return {@code true} if a service was enabled or a button target was removed,
+ * @return {@code true} if the lists of enabled services or buttons were changed,
* {@code false} otherwise.
*/
@VisibleForTesting
@@ -824,6 +824,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState.getBindingServicesLocked().remove(comp);
userState.getCrashedServicesLocked().remove(comp);
enabledServicesChanged = true;
+ break;
}
}
}
@@ -851,132 +852,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return mPackageMonitor;
}
- private void registerBroadcastReceivers() {
- mPackageMonitor = new PackageMonitor(true) {
- @Override
- public void onSomePackagesChanged() {
- if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
- mTraceManager.logTrace(LOG_TAG + ".PM.onSomePackagesChanged",
- FLAGS_PACKAGE_BROADCAST_RECEIVER);
- }
-
- final int userId = getChangingUserId();
- List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = null;
- List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = null;
- parsedAccessibilityServiceInfos = parseAccessibilityServiceInfos(userId);
- parsedAccessibilityShortcutInfos = parseAccessibilityShortcutInfos(userId);
- synchronized (mLock) {
- // Only the profile parent can install accessibility services.
- // Therefore we ignore packages from linked profiles.
- if (userId != mCurrentUserId) {
- return;
- }
- onSomePackagesChangedLocked(parsedAccessibilityServiceInfos,
- parsedAccessibilityShortcutInfos);
- }
- }
-
- @Override
- public void onPackageUpdateFinished(String packageName, int uid) {
- // The package should already be removed from mBoundServices, and added into
- // mBindingServices in binderDied() during updating. Remove services from this
- // package from mBindingServices, and then update the user state to re-bind new
- // versions of them.
- if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
- mTraceManager.logTrace(LOG_TAG + ".PM.onPackageUpdateFinished",
- FLAGS_PACKAGE_BROADCAST_RECEIVER,
- "packageName=" + packageName + ";uid=" + uid);
- }
- final int userId = getChangingUserId();
- List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = null;
- List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = null;
- parsedAccessibilityServiceInfos = parseAccessibilityServiceInfos(userId);
- parsedAccessibilityShortcutInfos = parseAccessibilityShortcutInfos(userId);
- synchronized (mLock) {
- if (userId != mCurrentUserId) {
- return;
- }
- final AccessibilityUserState userState = getUserStateLocked(userId);
- final boolean reboundAService = userState.getBindingServicesLocked().removeIf(
- component -> component != null
- && component.getPackageName().equals(packageName))
- || userState.mCrashedServices.removeIf(component -> component != null
- && component.getPackageName().equals(packageName));
- // Reloads the installed services info to make sure the rebound service could
- // get a new one.
- userState.mInstalledServices.clear();
- final boolean configurationChanged;
- configurationChanged = readConfigurationForUserStateLocked(userState,
- parsedAccessibilityServiceInfos, parsedAccessibilityShortcutInfos);
- if (reboundAService || configurationChanged) {
- onUserStateChangedLocked(userState);
- }
- // Passing 0 for restoreFromSdkInt to have this migration check execute each
- // time. It can make sure a11y button settings are correctly if there's an a11y
- // service updated and modifies the a11y button configuration.
- migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName,
- /* restoreFromSdkInt = */0);
- }
- }
-
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
- mTraceManager.logTrace(LOG_TAG + ".PM.onPackageRemoved",
- FLAGS_PACKAGE_BROADCAST_RECEIVER,
- "packageName=" + packageName + ";uid=" + uid);
- }
-
- synchronized (mLock) {
- final int userId = getChangingUserId();
- // Only the profile parent can install accessibility services.
- // Therefore we ignore packages from linked profiles.
- if (userId != mCurrentUserId) {
- return;
- }
- onPackageRemovedLocked(packageName);
- }
- }
-
- /**
- * Handles instances in which a package or packages have forcibly stopped.
- *
- * @param intent intent containing package event information.
- * @param uid linux process user id (different from Android user id).
- * @param packages array of package names that have stopped.
- * @param doit whether to try and handle the stop or just log the trace.
- *
- * @return {@code true} if package should be restarted, {@code false} otherwise.
- */
- @Override
- public boolean onHandleForceStop(Intent intent, String[] packages,
- int uid, boolean doit) {
- if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
- mTraceManager.logTrace(LOG_TAG + ".PM.onHandleForceStop",
- FLAGS_PACKAGE_BROADCAST_RECEIVER,
- "intent=" + intent + ";packages=" + Arrays.toString(packages)
- + ";uid=" + uid + ";doit=" + doit);
- }
- synchronized (mLock) {
- final int userId = getChangingUserId();
- // Only the profile parent can install accessibility services.
- // Therefore we ignore packages from linked profiles.
- if (userId != mCurrentUserId) {
- return false;
- }
- final AccessibilityUserState userState = getUserStateLocked(userId);
-
- if (doit && onPackagesForceStoppedLocked(packages, userState)) {
- onUserStateChangedLocked(userState);
- return false;
- } else {
- return true;
- }
- }
- }
- };
+ @VisibleForTesting
+ void setPackageMonitor(PackageMonitor monitor) {
+ mPackageMonitor = monitor;
+ }
+ private void registerBroadcastReceivers() {
// package changes
+ mPackageMonitor = new ManagerPackageMonitor(this);
mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
// user change and unlock
@@ -992,7 +875,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
@Override
public void onReceive(Context context, Intent intent) {
if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_USER_BROADCAST_RECEIVER)) {
- mTraceManager.logTrace(LOG_TAG + ".BR.onReceive", FLAGS_USER_BROADCAST_RECEIVER,
+ mTraceManager.logTrace(
+ LOG_TAG + ".BR.onReceive",
+ FLAGS_USER_BROADCAST_RECEIVER,
"context=" + context + ";intent=" + intent);
}
@@ -1045,7 +930,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
setNonA11yToolNotificationToMatchSafetyCenter();
}
};
- mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, mMainHandler,
+ mContext.registerReceiverAsUser(
+ receiver, UserHandle.ALL, filter, null, mMainHandler,
Context.RECEIVER_EXPORTED);
if (!android.companion.virtual.flags.Flags.vdmPublicApis()) {
@@ -4371,7 +4257,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
);
if (!targetWithNoTile.isEmpty()) {
- throw new IllegalArgumentException(
+ Slog.e(LOG_TAG,
"Unable to add/remove Tiles for a11y features: " + targetWithNoTile
+ "as the Tiles aren't provided");
}
@@ -6223,6 +6109,162 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ @VisibleForTesting
+ public static class ManagerPackageMonitor extends PackageMonitor {
+ private final AccessibilityManagerService mManagerService;
+ public ManagerPackageMonitor(AccessibilityManagerService managerService) {
+ super(/* supportsPackageRestartQuery = */ true);
+ mManagerService = managerService;
+ }
+
+ @Override
+ public void onSomePackagesChanged() {
+ if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
+ FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
+ mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onSomePackagesChanged",
+ FLAGS_PACKAGE_BROADCAST_RECEIVER);
+ }
+
+ final int userId = getChangingUserId();
+ List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = mManagerService
+ .parseAccessibilityServiceInfos(userId);
+ List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = mManagerService
+ .parseAccessibilityShortcutInfos(userId);
+ synchronized (mManagerService.getLock()) {
+ // Only the profile parent can install accessibility services.
+ // Therefore we ignore packages from linked profiles.
+ if (userId != mManagerService.getCurrentUserIdLocked()) {
+ return;
+ }
+ mManagerService.onSomePackagesChangedLocked(parsedAccessibilityServiceInfos,
+ parsedAccessibilityShortcutInfos);
+ }
+ }
+
+ @Override
+ public void onPackageUpdateFinished(String packageName, int uid) {
+ // The package should already be removed from mBoundServices, and added into
+ // mBindingServices in binderDied() during updating. Remove services from this
+ // package from mBindingServices, and then update the user state to re-bind new
+ // versions of them.
+ if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
+ FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
+ mManagerService.mTraceManager.logTrace(
+ LOG_TAG + ".PM.onPackageUpdateFinished",
+ FLAGS_PACKAGE_BROADCAST_RECEIVER,
+ "packageName=" + packageName + ";uid=" + uid);
+ }
+ final int userId = getChangingUserId();
+ List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = mManagerService
+ .parseAccessibilityServiceInfos(userId);
+ List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos =
+ mManagerService.parseAccessibilityShortcutInfos(userId);
+ synchronized (mManagerService.getLock()) {
+ if (userId != mManagerService.getCurrentUserIdLocked()) {
+ return;
+ }
+ final AccessibilityUserState userState = mManagerService.getUserStateLocked(userId);
+ final boolean reboundAService = userState.getBindingServicesLocked().removeIf(
+ component -> component != null
+ && component.getPackageName().equals(packageName))
+ || userState.mCrashedServices.removeIf(component -> component != null
+ && component.getPackageName().equals(packageName));
+ // Reloads the installed services info to make sure the rebound service could
+ // get a new one.
+ userState.mInstalledServices.clear();
+ final boolean configurationChanged;
+ configurationChanged = mManagerService.readConfigurationForUserStateLocked(
+ userState, parsedAccessibilityServiceInfos,
+ parsedAccessibilityShortcutInfos);
+ if (reboundAService || configurationChanged) {
+ mManagerService.onUserStateChangedLocked(userState);
+ }
+ // Passing 0 for restoreFromSdkInt to have this migration check execute each
+ // time. It can make sure a11y button settings are correctly if there's an a11y
+ // service updated and modifies the a11y button configuration.
+ mManagerService.migrateAccessibilityButtonSettingsIfNecessaryLocked(
+ userState, packageName, /* restoreFromSdkInt = */0);
+ }
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
+ FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
+ mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onPackageRemoved",
+ FLAGS_PACKAGE_BROADCAST_RECEIVER,
+ "packageName=" + packageName + ";uid=" + uid);
+ }
+
+ synchronized (mManagerService.getLock()) {
+ final int userId = getChangingUserId();
+ // Only the profile parent can install accessibility services.
+ // Therefore we ignore packages from linked profiles.
+ if (userId != mManagerService.getCurrentUserIdLocked()) {
+ return;
+ }
+ mManagerService.onPackageRemovedLocked(packageName);
+ }
+ }
+
+ /**
+ * Handles instances in which a package or packages have forcibly stopped.
+ *
+ * @param intent intent containing package event information.
+ * @param uid linux process user id (different from Android user id).
+ * @param packages array of package names that have stopped.
+ * @param doit whether to try and handle the stop or just log the trace.
+ *
+ * @return {@code true} if doit == {@code false}
+ * and at least one of the provided packages is enabled.
+ * In any other case, returns {@code false}.
+ * This is to indicate whether further action is necessary.
+ */
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages,
+ int uid, boolean doit) {
+ if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
+ FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
+ mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onHandleForceStop",
+ FLAGS_PACKAGE_BROADCAST_RECEIVER,
+ "intent=" + intent + ";packages=" + Arrays.toString(packages)
+ + ";uid=" + uid + ";doit=" + doit);
+ }
+ synchronized (mManagerService.getLock()) {
+ final int userId = getChangingUserId();
+ // Only the profile parent can install accessibility services.
+ // Therefore we ignore packages from linked profiles.
+ if (userId != mManagerService.getCurrentUserIdLocked()) {
+ return false;
+ }
+ final AccessibilityUserState userState = mManagerService.getUserStateLocked(userId);
+
+ if (Flags.managerPackageMonitorLogicFix()) {
+ if (!doit) {
+ // if we're not handling the stop here, then we only need to know
+ // if any of the force-stopped packages are currently enabled.
+ return userState.mEnabledServices.stream().anyMatch(
+ (comp) -> Arrays.stream(packages).anyMatch(
+ (pkg) -> pkg.equals(comp.getPackageName()))
+ );
+ } else if (mManagerService.onPackagesForceStoppedLocked(packages, userState)) {
+ mManagerService.onUserStateChangedLocked(userState);
+ }
+ return false;
+ } else {
+ // this old logic did not properly indicate when base packageMonitor's routine
+ // should handle stopping the package.
+ if (doit && mManagerService.onPackagesForceStoppedLocked(packages, userState)) {
+ mManagerService.onUserStateChangedLocked(userState);
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
void sendPendingWindowStateChangedEventsForAvailableWindowLocked(int windowId) {
final int eventSize = mSendWindowStateChangedEventRunnables.size();
for (int i = eventSize - 1; i >= 0; i--) {
diff --git a/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING b/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
index 340bc327fc7f..caa877c2b964 100644
--- a/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
+++ b/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
@@ -81,9 +81,6 @@
"name": "CtsPermissionTestCases",
"options": [
{
- "include-filter": "android.permissionmultidevice.cts.DeviceAwarePermissionGrantTest"
- },
- {
"include-filter": "android.permission.cts.DevicePermissionsTest"
},
{
@@ -93,6 +90,14 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "CtsPermissionMultiDeviceTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index a61925732256..c1d59db1f0c7 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -138,6 +138,11 @@ public class PackageWatchdog {
static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10);
+ // Time needed to apply mitigation
+ private static final String MITIGATION_WINDOW_MS =
+ "persist.device_config.configuration.mitigation_window_ms";
+ private static final long DEFAULT_MITIGATION_WINDOW_MS = TimeUnit.SECONDS.toMillis(5);
+
// Threshold level at which or above user might experience significant disruption.
private static final String MAJOR_USER_IMPACT_LEVEL_THRESHOLD =
"persist.device_config.configuration.major_user_impact_level_threshold";
@@ -210,6 +215,9 @@ public class PackageWatchdog {
@GuardedBy("mLock")
private boolean mSyncRequired = false;
+ @GuardedBy("mLock")
+ private long mLastMitigation = -1000000;
+
@FunctionalInterface
@VisibleForTesting
interface SystemClock {
@@ -400,6 +408,14 @@ public class PackageWatchdog {
Slog.w(TAG, "Could not resolve a list of failing packages");
return;
}
+ synchronized (mLock) {
+ final long now = mSystemClock.uptimeMillis();
+ if (now >= mLastMitigation
+ && (now - mLastMitigation) < getMitigationWindowMs()) {
+ Slog.i(TAG, "Skipping onPackageFailure mitigation");
+ return;
+ }
+ }
mLongTaskHandler.post(() -> {
synchronized (mLock) {
if (mAllObservers.isEmpty()) {
@@ -500,10 +516,17 @@ public class PackageWatchdog {
int currentObserverImpact,
int mitigationCount) {
if (currentObserverImpact < getUserImpactLevelLimit()) {
+ synchronized (mLock) {
+ mLastMitigation = mSystemClock.uptimeMillis();
+ }
currentObserverToNotify.execute(versionedPackage, failureReason, mitigationCount);
}
}
+ private long getMitigationWindowMs() {
+ return SystemProperties.getLong(MITIGATION_WINDOW_MS, DEFAULT_MITIGATION_WINDOW_MS);
+ }
+
/**
* Called when the system server boots. If the system server is detected to be in a boot loop,
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index a508ebfdb950..8c1bb3b0cb71 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -1783,7 +1783,13 @@ public class SystemConfig {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = Process.getGidForName(gidStr);
- perm.gids = appendInt(perm.gids, gid);
+ if (gid != -1) {
+ perm.gids = appendInt(perm.gids, gid);
+ } else {
+ Slog.w(TAG, "<group> with unknown gid \""
+ + gidStr + " for permission " + name + " in "
+ + parser.getPositionDescription());
+ }
} else {
Slog.w(TAG, "<group> without gid at "
+ parser.getPositionDescription());
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 04e85c7f117a..a3b6d806c6ce 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -134,6 +134,13 @@
},
{
"name": "CtsSuspendAppsTestCases"
+ },
+ {
+ "name": "CtsWindowManagerBackgroundActivityTestCases",
+ "file_patterns": [
+ "Background.*\\.java",
+ "Activity.*\\.java"
+ ]
}
],
"presubmit-large": [
@@ -189,18 +196,16 @@
"name": "SelinuxFrameworksTests"
},
{
- "name": "CtsWindowManagerBackgroundActivityTestCases",
- "file_patterns": [
- "Background.*\\.java",
- "Activity.*\\.java"
- ]
- },
- {
"name": "WmTests",
"file_patterns": [
"Background.*\\.java",
"Activity.*\\.java"
+ ],
+ "options": [
+ {
+ "include-filter": "com.android.server.wm.BackgroundActivityStart*"
+ }
]
}
- ]
+ ]
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 00d8efa764ce..316937c8280a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19975,6 +19975,26 @@ public class ActivityManagerService extends IActivityManager.Stub
addStartInfoTimestampInternal(key, timestampNs, userId, uid);
}
+
+ @Override
+ public void killApplicationSync(String pkgName, int appId, int userId,
+ String reason, int exitInfoReason) {
+ if (pkgName == null) {
+ return;
+ }
+ // Make sure the uid is valid.
+ if (appId < 0) {
+ Slog.w(TAG, "Invalid appid specified for pkg : " + pkgName);
+ return;
+ }
+ synchronized (ActivityManagerService.this) {
+ ActivityManagerService.this.forceStopPackageLocked(pkgName, appId,
+ /* callerWillRestart= */ false, /*purgeCache= */ false,
+ /* doit= */ true, /* evenPersistent= */ false,
+ /* uninstalling= */ false, /* packageStateStopped= */ false,
+ userId, reason, exitInfoReason);
+ }
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 4f841497b201..58732fd200d2 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -159,6 +159,8 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* All information we are collecting about things that can happen that impact
@@ -409,26 +411,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub
com.android.internal.R.bool.config_batteryStatsResetOnUnplugHighBatteryLevel);
final boolean resetOnUnplugAfterSignificantCharge = context.getResources().getBoolean(
com.android.internal.R.bool.config_batteryStatsResetOnUnplugAfterSignificantCharge);
- final long powerStatsThrottlePeriodCpu = context.getResources().getInteger(
- com.android.internal.R.integer.config_defaultPowerStatsThrottlePeriodCpu);
- final long powerStatsThrottlePeriodMobileRadio = context.getResources().getInteger(
- com.android.internal.R.integer.config_defaultPowerStatsThrottlePeriodMobileRadio);
- final long powerStatsThrottlePeriodWifi = context.getResources().getInteger(
- com.android.internal.R.integer.config_defaultPowerStatsThrottlePeriodWifi);
- mBatteryStatsConfig =
+ BatteryStatsImpl.BatteryStatsConfig.Builder batteryStatsConfigBuilder =
new BatteryStatsImpl.BatteryStatsConfig.Builder()
.setResetOnUnplugHighBatteryLevel(resetOnUnplugHighBatteryLevel)
- .setResetOnUnplugAfterSignificantCharge(resetOnUnplugAfterSignificantCharge)
- .setPowerStatsThrottlePeriodMillis(
- BatteryConsumer.POWER_COMPONENT_CPU,
- powerStatsThrottlePeriodCpu)
- .setPowerStatsThrottlePeriodMillis(
- BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
- powerStatsThrottlePeriodMobileRadio)
- .setPowerStatsThrottlePeriodMillis(
- BatteryConsumer.POWER_COMPONENT_WIFI,
- powerStatsThrottlePeriodWifi)
- .build();
+ .setResetOnUnplugAfterSignificantCharge(
+ resetOnUnplugAfterSignificantCharge);
+ setPowerStatsThrottlePeriods(batteryStatsConfigBuilder, context.getResources().getString(
+ com.android.internal.R.string.config_powerStatsThrottlePeriods));
+ mBatteryStatsConfig = batteryStatsConfigBuilder.build();
mPowerStatsUidResolver = new PowerStatsUidResolver();
mStats = new BatteryStatsImpl(mBatteryStatsConfig, Clock.SYSTEM_CLOCK, mMonotonicClock,
systemDir, mHandler, this, this, mUserManagerUserInfoProvider, mPowerProfile,
@@ -515,6 +505,26 @@ public final class BatteryStatsService extends IBatteryStats.Stub
return config;
}
+ private void setPowerStatsThrottlePeriods(BatteryStatsImpl.BatteryStatsConfig.Builder builder,
+ String configString) {
+ Matcher matcher = Pattern.compile("([^:]+):(\\d+)\\s*").matcher(configString);
+ while (matcher.find()) {
+ String powerComponentName = matcher.group(1);
+ long throttlePeriod;
+ try {
+ throttlePeriod = Long.parseLong(matcher.group(2));
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException(
+ "Invalid config_powerStatsThrottlePeriods format: " + configString);
+ }
+ if (powerComponentName.equals("*")) {
+ builder.setDefaultPowerStatsThrottlePeriodMillis(throttlePeriod);
+ } else {
+ builder.setPowerStatsThrottlePeriodMillis(powerComponentName, throttlePeriod);
+ }
+ }
+ }
+
/**
* Creates an instance of BatteryStatsService and restores data from stored state.
*/
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 6779f7a37f20..a5449a0f0431 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -37,6 +37,7 @@ import static android.os.Process.startWebView;
import static android.system.OsConstants.EAGAIN;
import static com.android.sdksandbox.flags.Flags.selinuxSdkSandboxAudit;
+import static com.android.sdksandbox.flags.Flags.selinuxSdkSandboxInputSelector;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
@@ -2065,11 +2066,15 @@ public final class ProcessList {
}
}
- return app.info.seInfo
- + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser) + extraInfo;
+ if (selinuxSdkSandboxInputSelector()) {
+ return app.info.seInfo + extraInfo + TextUtils.emptyIfNull(app.info.seInfoUser);
+ } else {
+ return app.info.seInfo
+ + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser)
+ + extraInfo;
+ }
}
-
@GuardedBy("mService")
boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 7dcd95232374..9bf5c2174d2c 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -157,6 +157,7 @@ public class SettingsToPropertiesMapper {
"car_telemetry",
"codec_fwk",
"companion",
+ "com_android_adbd",
"content_protection",
"context_hub",
"core_experiments_team_internal",
@@ -264,11 +265,11 @@ public class SettingsToPropertiesMapper {
Uri settingUri = Settings.Global.getUriFor(globalSetting);
String propName = makePropertyName(GLOBAL_SETTINGS_CATEGORY, globalSetting);
if (settingUri == null) {
- log("setting uri is null for globalSetting " + globalSetting);
+ logErr("setting uri is null for globalSetting " + globalSetting);
continue;
}
if (propName == null) {
- log("invalid prop name for globalSetting " + globalSetting);
+ logErr("invalid prop name for globalSetting " + globalSetting);
continue;
}
@@ -296,7 +297,7 @@ public class SettingsToPropertiesMapper {
for (String key : properties.getKeyset()) {
String propertyName = makePropertyName(scope, key);
if (propertyName == null) {
- log("unable to construct system property for " + scope + "/"
+ logErr("unable to construct system property for " + scope + "/"
+ key);
return;
}
@@ -308,7 +309,7 @@ public class SettingsToPropertiesMapper {
// sys prop slot can be removed.
String aconfigPropertyName = makeAconfigFlagPropertyName(scope, key);
if (aconfigPropertyName == null) {
- log("unable to construct system property for " + scope + "/"
+ logErr("unable to construct system property for " + scope + "/"
+ key);
return;
}
@@ -326,7 +327,7 @@ public class SettingsToPropertiesMapper {
for (String key : properties.getKeyset()) {
String aconfigPropertyName = makeAconfigFlagPropertyName(scope, key);
if (aconfigPropertyName == null) {
- log("unable to construct system property for " + scope + "/"
+ logErr("unable to construct system property for " + scope + "/"
+ key);
return;
}
@@ -356,7 +357,7 @@ public class SettingsToPropertiesMapper {
if (!propertyName.matches(SYSTEM_PROPERTY_VALID_CHARACTERS_REGEX)
|| propertyName.contains(SYSTEM_PROPERTY_INVALID_SUBSTRING)) {
- log("unable to construct system property for " + actualNamespace
+ logErr("unable to construct system property for " + actualNamespace
+ "/" + flagName);
continue;
}
@@ -394,9 +395,9 @@ public class SettingsToPropertiesMapper {
try{
client.connect(new LocalSocketAddress(
"aconfigd", LocalSocketAddress.Namespace.RESERVED));
- log("connected to aconfigd socket");
+ Slog.d(TAG, "connected to aconfigd socket");
} catch (IOException ioe) {
- log("failed to connect to aconfigd socket", ioe);
+ logErr("failed to connect to aconfigd socket", ioe);
return null;
}
@@ -406,7 +407,7 @@ public class SettingsToPropertiesMapper {
inputStream = new DataInputStream(client.getInputStream());
outputStream = new DataOutputStream(client.getOutputStream());
} catch (IOException ioe) {
- log("failed to get local socket iostreams", ioe);
+ logErr("failed to get local socket iostreams", ioe);
return null;
}
@@ -415,9 +416,9 @@ public class SettingsToPropertiesMapper {
byte[] requests_bytes = requests.getBytes();
outputStream.writeInt(requests_bytes.length);
outputStream.write(requests_bytes, 0, requests_bytes.length);
- log("flag override requests sent to aconfigd");
+ Slog.d(TAG, "flag override requests sent to aconfigd");
} catch (IOException ioe) {
- log("failed to send requests to aconfigd", ioe);
+ logErr("failed to send requests to aconfigd", ioe);
return null;
}
@@ -425,10 +426,10 @@ public class SettingsToPropertiesMapper {
try {
int num_bytes = inputStream.readInt();
ProtoInputStream returns = new ProtoInputStream(inputStream);
- log("received " + num_bytes + " bytes back from aconfigd");
+ Slog.d(TAG, "received " + num_bytes + " bytes back from aconfigd");
return returns;
} catch (IOException ioe) {
- log("failed to read requests return from aconfigd", ioe);
+ logErr("failed to read requests return from aconfigd", ioe);
return null;
}
}
@@ -461,18 +462,18 @@ public class SettingsToPropertiesMapper {
long msgsToken = proto.start(StorageReturnMessages.MSGS);
switch (proto.nextField()) {
case (int) StorageReturnMessage.FLAG_OVERRIDE_MESSAGE:
- log("successfully handled override requests");
+ Slog.d(TAG, "successfully handled override requests");
long msgToken = proto.start(StorageReturnMessage.FLAG_OVERRIDE_MESSAGE);
proto.end(msgToken);
break;
case (int) StorageReturnMessage.ERROR_MESSAGE:
String errmsg = proto.readString(StorageReturnMessage.ERROR_MESSAGE);
- log("override request failed: " + errmsg);
+ Slog.d(TAG, "override request failed: " + errmsg);
break;
case ProtoInputStream.NO_MORE_FIELDS:
break;
default:
- log("invalid message type, expecting only flag override return or error message");
+ logErr("invalid message type, expecting only flag override return or error message");
break;
}
proto.end(msgsToken);
@@ -480,7 +481,7 @@ public class SettingsToPropertiesMapper {
case ProtoInputStream.NO_MORE_FIELDS:
return;
default:
- log("invalid message type, expect storage return message");
+ logErr("invalid message type, expect storage return message");
break;
}
}
@@ -501,14 +502,14 @@ public class SettingsToPropertiesMapper {
int idx = flagName.indexOf(":");
if (idx == -1 || idx == flagName.length() - 1 || idx == 0) {
- log("invalid local flag override: " + flagName);
+ logErr("invalid local flag override: " + flagName);
continue;
}
String actualNamespace = flagName.substring(0, idx);
String fullFlagName = flagName.substring(idx+1);
idx = fullFlagName.lastIndexOf(".");
if (idx == -1) {
- log("invalid flag name: " + fullFlagName);
+ logErr("invalid flag name: " + fullFlagName);
continue;
}
String packageName = fullFlagName.substring(0, idx);
@@ -528,7 +529,7 @@ public class SettingsToPropertiesMapper {
try {
parseAndLogAconfigdReturn(returns);
} catch (IOException ioe) {
- log("failed to parse aconfigd return", ioe);
+ logErr("failed to parse aconfigd return", ioe);
}
}
@@ -572,7 +573,7 @@ public class SettingsToPropertiesMapper {
for (String property_name : property_names) {
String[] segments = property_name.split("\\.");
if (segments.length < 3) {
- log("failed to extract category name from property " + property_name);
+ logErr("failed to extract category name from property " + property_name);
continue;
}
categories.add(segments[2]);
@@ -617,7 +618,7 @@ public class SettingsToPropertiesMapper {
String stagedValue = flagValuesToStage.get(fullFlagName);
int idx = fullFlagName.lastIndexOf(".");
if (idx == -1) {
- log("invalid flag name: " + fullFlagName);
+ logErr("invalid flag name: " + fullFlagName);
continue;
}
String packageName = fullFlagName.substring(0, idx);
@@ -638,7 +639,7 @@ public class SettingsToPropertiesMapper {
try {
parseAndLogAconfigdReturn(returns);
} catch (IOException ioe) {
- log("failed to parse aconfigd return", ioe);
+ logErr("failed to parse aconfigd return", ioe);
}
}
@@ -680,7 +681,7 @@ public class SettingsToPropertiesMapper {
for (String flagName : properties.getKeyset()) {
int idx = flagName.indexOf(NAMESPACE_REBOOT_STAGING_DELIMITER);
if (idx == -1 || idx == flagName.length() - 1 || idx == 0) {
- log("invalid staged flag: " + flagName);
+ logErr("invalid staged flag: " + flagName);
continue;
}
String actualNamespace = flagName.substring(0, idx);
@@ -731,7 +732,7 @@ public class SettingsToPropertiesMapper {
}
value = "";
} else if (value.length() > SYSTEM_PROPERTY_MAX_LENGTH) {
- log("key=" + key + " value=" + value + " exceeds system property max length.");
+ logErr("key=" + key + " value=" + value + " exceeds system property max length.");
return;
}
@@ -741,11 +742,11 @@ public class SettingsToPropertiesMapper {
// Failure to set a property can be caused by SELinux denial. This usually indicates
// that the property wasn't allowlisted in sepolicy.
// No need to report it on all user devices, only on debug builds.
- log("Unable to set property " + key + " value '" + value + "'", e);
+ logErr("Unable to set property " + key + " value '" + value + "'", e);
}
}
- private static void log(String msg, Exception e) {
+ private static void logErr(String msg, Exception e) {
if (Build.IS_DEBUGGABLE) {
Slog.wtf(TAG, msg, e);
} else {
@@ -753,7 +754,7 @@ public class SettingsToPropertiesMapper {
}
}
- private static void log(String msg) {
+ private static void logErr(String msg) {
if (Build.IS_DEBUGGABLE) {
Slog.wtf(TAG, msg);
} else {
@@ -771,7 +772,7 @@ public class SettingsToPropertiesMapper {
br.close();
} catch (IOException ioe) {
- log("failed to read file " + RESET_RECORD_FILE_PATH, ioe);
+ logErr("failed to read file " + RESET_RECORD_FILE_PATH, ioe);
}
return content;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 46061a56631c..275c9309ffc9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -206,6 +206,10 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
launchDeviceDiscovery();
startQueuedActions();
if (!mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) {
+ if (hasAction(RequestActiveSourceAction.class)) {
+ Slog.i(TAG, "RequestActiveSourceAction is in progress. Restarting.");
+ removeAction(RequestActiveSourceAction.class);
+ }
addAndStartAction(new RequestActiveSourceAction(this, new IHdmiControlCallback.Stub() {
@Override
public void onComplete(int result) {
@@ -1308,6 +1312,8 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
mService.sendCecCommand(
HdmiCecMessageBuilder.buildActiveSource(
getDeviceInfo().getLogicalAddress(), activePath));
+ updateActiveSource(getDeviceInfo().getLogicalAddress(), activePath,
+ "HdmiCecLocalDeviceTv#launchRoutingControl()");
}
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 936e8b6a28b6..cca73b5eabf0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1646,6 +1646,13 @@ public class HdmiControlService extends SystemService {
case Constants.MESSAGE_ROUTING_CHANGE:
case Constants.MESSAGE_SET_STREAM_PATH:
case Constants.MESSAGE_TEXT_VIEW_ON:
+ // RequestActiveSourceAction is started after the TV finished logical address
+ // allocation. This action is used by the TV to get the active source from the CEC
+ // network. If the TV sent a source changing CEC message, this action does not have
+ // to continue anymore.
+ if (isTvDeviceEnabled()) {
+ tv().removeAction(RequestActiveSourceAction.class);
+ }
sendCecCommandWithRetries(command, callback);
break;
default:
diff --git a/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java b/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
index d2504164a6df..539a00db45b8 100644
--- a/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
@@ -21,13 +21,20 @@ import android.hardware.hdmi.IHdmiControlCallback;
import android.util.Slog;
/**
- * Feature action that sends <Request Active Source> message and waits for <Active Source>.
+ * Feature action that sends <Request Active Source> message and waits for <Active Source> on TV
+ * panels.
+ * This action has a delay before sending <Request Active Source>. This is because it should wait
+ * for a possible request from LauncherX and can be cancelled if an <Active Source> message was
+ * received or the TV switched to another input.
*/
public class RequestActiveSourceAction extends HdmiCecFeatureAction {
private static final String TAG = "RequestActiveSourceAction";
+ // State to wait for the LauncherX to call the CEC API.
+ private static final int STATE_WAIT_FOR_LAUNCHERX_API_CALL = 1;
+
// State to wait for the <Active Source> message.
- private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 1;
+ private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 2;
// Number of retries <Request Active Source> is sent if no device answers this message.
private static final int MAX_SEND_RETRY_COUNT = 1;
@@ -43,10 +50,12 @@ public class RequestActiveSourceAction extends HdmiCecFeatureAction {
boolean start() {
Slog.v(TAG, "RequestActiveSourceAction started.");
- sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()));
+ mState = STATE_WAIT_FOR_LAUNCHERX_API_CALL;
- mState = STATE_WAIT_FOR_ACTIVE_SOURCE;
- addTimer(mState, HdmiConfig.TIMEOUT_MS);
+ // We wait for default timeout to allow the message triggered by the LauncherX API call to
+ // be sent by the TV and another default timeout in case the message has to be answered
+ // (e.g. TV sent a <Set Stream Path> or <Routing Change>).
+ addTimer(mState, HdmiConfig.TIMEOUT_MS * 2);
return true;
}
@@ -65,13 +74,23 @@ public class RequestActiveSourceAction extends HdmiCecFeatureAction {
if (mState != state) {
return;
}
- if (mState == STATE_WAIT_FOR_ACTIVE_SOURCE) {
- if (mSendRetryCount++ < MAX_SEND_RETRY_COUNT) {
+
+ switch (mState) {
+ case STATE_WAIT_FOR_LAUNCHERX_API_CALL:
+ mState = STATE_WAIT_FOR_ACTIVE_SOURCE;
sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()));
addTimer(mState, HdmiConfig.TIMEOUT_MS);
- } else {
- finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
- }
+ return;
+ case STATE_WAIT_FOR_ACTIVE_SOURCE:
+ if (mSendRetryCount++ < MAX_SEND_RETRY_COUNT) {
+ sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()));
+ addTimer(mState, HdmiConfig.TIMEOUT_MS);
+ } else {
+ finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
+ }
+ return;
+ default:
+ return;
}
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 8685d2c45762..8e85b81d9bd2 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -2671,24 +2671,6 @@ public class InputManagerService extends IInputManager.Stub
return null;
}
- private static class PointerDisplayIdChangedArgs {
- final int mPointerDisplayId;
- final float mXPosition;
- final float mYPosition;
- PointerDisplayIdChangedArgs(int pointerDisplayId, float xPosition, float yPosition) {
- mPointerDisplayId = pointerDisplayId;
- mXPosition = xPosition;
- mYPosition = yPosition;
- }
- }
-
- // Native callback.
- @SuppressWarnings("unused")
- @VisibleForTesting
- void onPointerDisplayIdChanged(int pointerDisplayId, float xPosition, float yPosition) {
- // TODO(b/311416205): Remove.
- }
-
@Override
@EnforcePermission(Manifest.permission.MONITOR_STICKY_MODIFIER_STATE)
public void registerStickyModifierStateListener(
diff --git a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
index 1c14fc1b08dd..fff0e6e1b995 100644
--- a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
+++ b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
@@ -133,6 +133,13 @@ public final class ImeTrackerService extends IImeTracker.Stub {
}
}
+ @Override
+ public void onDispatched(@NonNull ImeTracker.Token statsToken) {
+ synchronized (mLock) {
+ mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
+ }
+ }
+
/**
* Updates the IME request tracking token with new information available in IMMS.
*
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index b7091744c3b6..e862c7e96200 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -443,7 +443,16 @@ final class InputMethodBindingController {
mCurId = info.getId();
mLastBindTime = SystemClock.uptimeMillis();
- addFreshWindowToken();
+ final int displayIdToShowIme = mService.getDisplayIdToShowImeLocked();
+ mCurToken = new Binder();
+ mService.setCurTokenDisplayIdLocked(displayIdToShowIme);
+ if (DEBUG) {
+ Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
+ + displayIdToShowIme);
+ }
+ mWindowManagerInternal.addWindowToken(mCurToken,
+ WindowManager.LayoutParams.TYPE_INPUT_METHOD,
+ displayIdToShowIme, null /* options */);
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
null, null, null, mCurId, mCurSeq, false);
@@ -471,22 +480,6 @@ final class InputMethodBindingController {
}
@GuardedBy("ImfLock.class")
- private void addFreshWindowToken() {
- int displayIdToShowIme = mService.getDisplayIdToShowImeLocked();
- mCurToken = new Binder();
-
- mService.setCurTokenDisplayIdLocked(displayIdToShowIme);
-
- if (DEBUG) {
- Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
- + displayIdToShowIme);
- }
- mWindowManagerInternal.addWindowToken(mCurToken,
- WindowManager.LayoutParams.TYPE_INPUT_METHOD,
- displayIdToShowIme, null /* options */);
- }
-
- @GuardedBy("ImfLock.class")
private void unbindMainConnection() {
mContext.unbindService(mMainConnection);
mHasMainConnection = false;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodInfoUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodInfoUtils.java
index 6339686629f5..458c3598d7ae 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodInfoUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodInfoUtils.java
@@ -22,6 +22,7 @@ import static com.android.server.inputmethod.SubtypeUtils.SUBTYPE_MODE_KEYBOARD;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.os.Parcel;
import android.text.TextUtils;
import android.util.Slog;
import android.view.inputmethod.InputMethodInfo;
@@ -323,4 +324,24 @@ final class InputMethodInfoUtils {
return SubtypeUtils.containsSubtypeOf(imi, requiredLocale, checkCountry,
requiredSubtypeMode);
}
+
+ /**
+ * Marshals the given {@link InputMethodInfo} into a byte array.
+ *
+ * @param imi {@link InputMethodInfo} to be marshalled
+ * @return a byte array where the given {@link InputMethodInfo} is marshalled
+ */
+ @NonNull
+ static byte[] marshal(@NonNull InputMethodInfo imi) {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ parcel.writeTypedObject(imi, 0);
+ return parcel.marshall();
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 954f9bcd9c43..e5df42eaeea5 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -262,6 +262,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
private static final String HANDLER_THREAD_NAME = "android.imms";
+ private static final String PACKAGE_MONITOR_THREAD_NAME = "android.imms2";
/**
* When set, {@link #startInputUncheckedLocked} will return
@@ -281,10 +282,35 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@NonNull
private final String[] mNonPreemptibleInputMethods;
+ /**
+ * See {@link #shouldEnableExperimentalConcurrentMultiUserMode(Context)} about when set to be
+ * {@code true}.
+ */
+ private final boolean mExperimentalConcurrentMultiUserModeEnabled;
+
+ /**
+ * Returns {@code true} if experimental concurrent multi-user mode is enabled.
+ *
+ * <p>Currently not compatible with profiles (e.g. work profile).</p>
+ *
+ * @param context {@link Context} to be used to query
+ * {@link PackageManager#FEATURE_AUTOMOTIVE}
+ * @return {@code true} if experimental concurrent multi-user mode is enabled.
+ */
+ static boolean shouldEnableExperimentalConcurrentMultiUserMode(@NonNull Context context) {
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ && UserManager.isVisibleBackgroundUsersEnabled()
+ && context.getResources().getBoolean(android.R.bool.config_perDisplayFocusEnabled)
+ && Flags.concurrentInputMethods();
+ }
+
final Context mContext;
final Resources mRes;
private final Handler mHandler;
+ @NonNull
+ private final Handler mPackageMonitorHandler;
+
@MultiUserUnawareField
@UserIdInt
@GuardedBy("ImfLock.class")
@@ -1187,8 +1213,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
public static final class Lifecycle extends SystemService {
private final InputMethodManagerService mService;
+
public Lifecycle(Context context) {
- this(context, new InputMethodManagerService(context));
+ this(context, new InputMethodManagerService(context,
+ shouldEnableExperimentalConcurrentMultiUserMode(context)));
}
public Lifecycle(
@@ -1240,9 +1268,15 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@Override
public void onUserStarting(TargetUser user) {
// Called on ActivityManager thread.
- SecureSettingsWrapper.onUserStarting(user.getUserIdentifier());
+ final int userId = user.getUserIdentifier();
+ SecureSettingsWrapper.onUserStarting(userId);
synchronized (ImfLock.class) {
- mService.mUserDataRepository.getOrCreate(user.getUserIdentifier());
+ mService.mUserDataRepository.getOrCreate(userId);
+ if (mService.mExperimentalConcurrentMultiUserModeEnabled) {
+ if (mService.mCurrentUserId != userId) {
+ mService.experimentalInitializeVisibleBackgroundUserLocked(userId);
+ }
+ }
}
}
@@ -1263,6 +1297,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// We need to rebuild IMEs.
postInputMethodSettingUpdatedLocked(false /* resetDefaultEnabledIme */);
updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
+ } else if (mExperimentalConcurrentMultiUserModeEnabled) {
+ experimentalInitializeVisibleBackgroundUserLocked(userId);
}
}
}
@@ -1287,16 +1323,21 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mHandler.post(task);
}
- public InputMethodManagerService(Context context) {
- this(context, null, null);
+ public InputMethodManagerService(Context context,
+ boolean experimentalConcurrentMultiUserModeEnabled) {
+ this(context, experimentalConcurrentMultiUserModeEnabled, null, null, null);
}
@VisibleForTesting
InputMethodManagerService(
Context context,
+ boolean experimentalConcurrentMultiUserModeEnabled,
@Nullable ServiceThread serviceThreadForTesting,
+ @Nullable ServiceThread packageMonitorThreadForTesting,
@Nullable IntFunction<InputMethodBindingController> bindingControllerForTesting) {
synchronized (ImfLock.class) {
+ mExperimentalConcurrentMultiUserModeEnabled =
+ experimentalConcurrentMultiUserModeEnabled;
mContext = context;
mRes = context.getResources();
SecureSettingsWrapper.onStart(mContext);
@@ -1312,6 +1353,17 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
true /* allowIo */);
thread.start();
mHandler = Handler.createAsync(thread.getLooper(), this);
+ {
+ final ServiceThread packageMonitorThread =
+ packageMonitorThreadForTesting != null
+ ? packageMonitorThreadForTesting
+ : new ServiceThread(
+ PACKAGE_MONITOR_THREAD_NAME,
+ Process.THREAD_PRIORITY_FOREGROUND,
+ true /* allowIo */);
+ packageMonitorThread.start();
+ mPackageMonitorHandler = Handler.createAsync(packageMonitorThread.getLooper());
+ }
SystemLocaleWrapper.onStart(context, this::onActionLocaleChanged, mHandler);
mImeTrackerService = new ImeTrackerService(serviceThreadForTesting != null
? serviceThreadForTesting.getLooper() : Looper.getMainLooper());
@@ -1487,7 +1539,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// Note that in b/197848765 we want to see if we can keep the binding alive for better
// profile switching.
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- userData.mBindingController.unbindCurrentMethod();
+ final var bindingController = userData.mBindingController;
+ bindingController.unbindCurrentMethod();
unbindCurrentClientLocked(UnbindReason.SWITCH_USER);
@@ -1585,7 +1638,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
}, "Lazily initialize IMMS#mImeDrawsImeNavBarRes");
- mMyPackageMonitor.register(mContext, UserHandle.ALL, mHandler);
+ mMyPackageMonitor.register(mContext, UserHandle.ALL, mPackageMonitorHandler);
mSettingsObserver.registerContentObserverLocked(currentUserId);
final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
@@ -1613,8 +1666,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Returns true iff the caller is identified to be the current input method with the token.
- * @param token The window token given to the input method when it was started.
- * @return true if and only if non-null valid token is specified.
+ *
+ * @param token the window token given to the input method when it was started
+ * @return true if and only if non-null valid token is specified
*/
@GuardedBy("ImfLock.class")
private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
@@ -1706,9 +1760,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// Check if selected IME of current user supports handwriting.
if (userId == mCurrentUserId) {
final var userData = mUserDataRepository.getOrCreate(userId);
- return userData.mBindingController.supportsStylusHandwriting()
+ final var bindingController = userData.mBindingController;
+ return bindingController.supportsStylusHandwriting()
&& (!connectionless
- || userData.mBindingController.supportsConnectionlessStylusHandwriting());
+ || bindingController.supportsConnectionlessStylusHandwriting());
}
final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final InputMethodInfo imi = settings.getMethodMap().get(
@@ -1769,10 +1824,11 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Gets enabled subtypes of the specified {@link InputMethodInfo}.
*
- * @param imiId if null, returns enabled subtypes for the current {@link InputMethodInfo}.
+ * @param imiId if null, returns enabled subtypes for the current
+ * {@link InputMethodInfo}
* @param allowsImplicitlyEnabledSubtypes {@code true} to return the implicitly enabled
- * subtypes.
- * @param userId the user ID to be queried about.
+ * subtypes
+ * @param userId the user ID to be queried about
*/
@Override
public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
@@ -1816,10 +1872,11 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
* <p>As a general principle, IPCs from the application process that take
* {@link IInputMethodClient} will be rejected without this step.</p>
*
- * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
- * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
- * process
- * @param inputConnection communication channel for the fallback {@link InputConnection}
+ * @param client {@link android.os.Binder} proxy that is associated with the
+ * singleton instance of
+ * {@link android.view.inputmethod.InputMethodManager} that runs
+ * on the client process
+ * @param inputConnection communication channel for the fallback {@link InputConnection}
* @param selfReportedDisplayId self-reported display ID to which the client is associated.
* Whether the client is still allowed to access to this display
* or not needs to be evaluated every time the client interacts
@@ -1844,10 +1901,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
}
- // TODO(b/325515685): Move this method to InputMethodBindingController
/**
* Hide the IME if the removed user is the current user.
*/
+ // TODO(b/325515685): Move this method to InputMethodBindingController
@GuardedBy("ImfLock.class")
private void onClientRemoved(ClientState client) {
clearClientSessionLocked(client);
@@ -1904,7 +1961,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// following dependencies also need to be user independent: mCurClient, mBoundToMethod,
// getCurMethodLocked(), and mMenuController.
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- mCurClient.mClient.onUnbindMethod(userData.mBindingController.getSequenceNumber(),
+ final var bindingController = userData.mBindingController;
+ mCurClient.mClient.onUnbindMethod(bindingController.getSequenceNumber(),
unbindClientReason);
mCurClient.mSessionRequested = false;
mCurClient.mSessionRequestedForAccessibility = false;
@@ -1984,13 +2042,14 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final boolean restarting = !initial;
final Binder startInputToken = new Binder();
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ final var bindingController = userData.mBindingController;
final StartInputInfo info = new StartInputInfo(mCurrentUserId,
getCurTokenLocked(),
- mCurTokenDisplayId, userData.mBindingController.getCurId(), startInputReason,
+ getCurTokenDisplayIdLocked(), bindingController.getCurId(), startInputReason,
restarting, UserHandle.getUserId(mCurClient.mUid),
mCurClient.mSelfReportedDisplayId, mImeBindingState.mFocusedWindow, mCurEditorInfo,
mImeBindingState.mFocusedWindowSoftInputMode,
- userData.mBindingController.getSequenceNumber());
+ bindingController.getSequenceNumber());
mImeTargetWindowMap.put(startInputToken, mImeBindingState.mFocusedWindow);
mStartInputHistory.addEntry(info);
@@ -2002,7 +2061,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
if (mCurrentUserId == UserHandle.getUserId(
mCurClient.mUid)) {
mPackageManagerInternal.grantImplicitAccess(mCurrentUserId, null /* intent */,
- UserHandle.getAppId(userData.mBindingController.getCurMethodUid()),
+ UserHandle.getAppId(bindingController.getCurMethodUid()),
mCurClient.mUid, true /* direct */);
}
@@ -2023,20 +2082,20 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
null /* resultReceiver */, SoftInputShowHideReason.ATTACH_NEW_INPUT);
}
- final var curId = userData.mBindingController.getCurId();
+ final var curId = bindingController.getCurId();
final InputMethodInfo curInputMethodInfo = InputMethodSettingsRepository.get(mCurrentUserId)
.getMethodMap().get(curId);
final boolean suppressesSpellChecker =
curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
final SparseArray<IAccessibilityInputMethodSession> accessibilityInputMethodSessions =
createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
- if (userData.mBindingController.supportsStylusHandwriting() && hasSupportedStylusLocked()) {
+ if (bindingController.supportsStylusHandwriting() && hasSupportedStylusLocked()) {
mHwController.setInkWindowInitializer(new InkWindowInitializer());
}
return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
session.mSession, accessibilityInputMethodSessions,
(session.mChannel != null ? session.mChannel.dup() : null),
- curId, userData.mBindingController.getSequenceNumber(), suppressesSpellChecker);
+ curId, bindingController.getSequenceNumber(), suppressesSpellChecker);
}
@GuardedBy("ImfLock.class")
@@ -2130,7 +2189,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final boolean connectionWasActive = mCurInputConnection != null;
// Bump up the sequence for this client and attach it.
- userData.mBindingController.advanceSequenceNumber();
+ final var bindingController = userData.mBindingController;
+ bindingController.advanceSequenceNumber();
mCurClient = cs;
mCurInputConnection = inputConnection;
@@ -2153,7 +2213,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
if (connectionIsActive != connectionWasActive) {
mInputManagerInternal.notifyInputMethodConnectionActive(connectionIsActive);
}
- final var bindingController = userData.mBindingController;
// If configured, we want to avoid starting up the IME if it is not supposed to be showing
if (shouldPreventImeStartupLocked(selectedMethodId, startInputFlags,
@@ -2171,7 +2230,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// display ID.
final String curId = bindingController.getCurId();
if (curId != null && curId.equals(bindingController.getSelectedMethodId())
- && mDisplayIdToShowIme == mCurTokenDisplayId) {
+ && mDisplayIdToShowIme == getCurTokenDisplayIdLocked()) {
if (cs.mCurSession != null) {
// Fast case: if we are already connected to the input method,
// then just return it.
@@ -2202,11 +2261,13 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Update the current deviceId and return the relevant imeId for this device.
- * 1. If the device changes to virtual and its custom IME is not available, then disable IME.
- * 2. If the device changes to virtual with valid custom IME, then return the custom IME. If
- * the old device was default, then store the current imeId so it can be restored.
- * 3. If the device changes to default, restore the default device IME.
- * 4. Otherwise keep the current imeId.
+ *
+ * <p>1. If the device changes to virtual and its custom IME is not available, then disable
+ * IME.</p>
+ * <p>2. If the device changes to virtual with valid custom IME, then return the custom IME. If
+ * the old device was default, then store the current imeId so it can be restored.</p>
+ * <p>3. If the device changes to default, restore the default device IME.</p>
+ * <p>4. Otherwise keep the current imeId.</p>
*/
@GuardedBy("ImfLock.class")
private String computeCurrentDeviceMethodIdLocked(String currentMethodId) {
@@ -2304,7 +2365,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@Nullable
private InputBindResult tryReuseConnectionLocked(@NonNull UserDataRepository.UserData userData,
@NonNull ClientState cs) {
- if (userData.mBindingController.hasMainConnection()) {
+ final var bindingController = userData.mBindingController;
+ if (bindingController.hasMainConnection()) {
if (getCurMethodLocked() != null) {
// Return to client, and we will get back with it when
// we have had a session made for it.
@@ -2313,10 +2375,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
null, null, null,
- userData.mBindingController.getCurId(),
- userData.mBindingController.getSequenceNumber(), false);
+ bindingController.getCurId(),
+ bindingController.getSequenceNumber(), false);
} else {
- final long lastBindTime = userData.mBindingController.getLastBindTime();
+ final long lastBindTime = bindingController.getLastBindTime();
long bindingDuration = SystemClock.uptimeMillis() - lastBindTime;
if (bindingDuration < TIME_TO_RECONNECT) {
// In this case we have connected to the service, but
@@ -2329,8 +2391,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
null, null, null,
- userData.mBindingController.getCurId(),
- userData.mBindingController.getSequenceNumber(), false);
+ bindingController.getCurId(),
+ bindingController.getSequenceNumber(), false);
} else {
EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
getSelectedMethodIdLocked(), bindingDuration, 0);
@@ -2349,12 +2411,12 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Find the display where the IME should be shown.
*
- * @param displayId the ID of the display where the IME client target is.
- * @param checker instance of {@link ImeDisplayValidator} which is used for
- * checking display config to adjust the final target display.
- * @return The ID of the display where the IME should be shown or
- * {@link android.view.Display#INVALID_DISPLAY} if the display has an ImePolicy of
- * {@link WindowManager#DISPLAY_IME_POLICY_HIDE}.
+ * @param displayId the ID of the display where the IME client target is
+ * @param checker instance of {@link ImeDisplayValidator} which is used for
+ * checking display config to adjust the final target display
+ * @return the ID of the display where the IME should be shown or
+ * {@link android.view.Display#INVALID_DISPLAY} if the display has an ImePolicy of
+ * {@link WindowManager#DISPLAY_IME_POLICY_HIDE}
*/
static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
@@ -2377,7 +2439,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
void initializeImeLocked(@NonNull IInputMethodInvoker inputMethod, @NonNull IBinder token) {
if (DEBUG) {
Slog.v(TAG, "Sending attach of token: " + token + " for display: "
- + mCurTokenDisplayId);
+ + getCurTokenDisplayIdLocked());
}
inputMethod.initializeInternal(token, new InputMethodPrivilegedOperationsImpl(this, token),
getInputMethodNavButtonFlagsLocked());
@@ -2457,13 +2519,14 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@GuardedBy("ImfLock.class")
void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- userData.mBindingController.setSelectedMethodId(null);
+ final var bindingController =
+ mUserDataRepository.getOrCreate(mCurrentUserId).mBindingController;
+ bindingController.setSelectedMethodId(null);
// Callback before clean-up binding states.
// TODO(b/338461930): Check if this is still necessary or not.
onUnbindCurrentMethodByReset();
- userData.mBindingController.unbindCurrentMethod();
+ bindingController.unbindCurrentMethod();
unbindCurrentClientLocked(unbindClientReason);
}
@@ -2666,9 +2729,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
// Whether the current display has a navigation bar. When this is false (e.g. emulator),
// the IME should not draw the IME navigation bar.
+ final int tokenDisplayId = getCurTokenDisplayIdLocked();
final boolean hasNavigationBar = mWindowManagerInternal
- .hasNavigationBar(mCurTokenDisplayId != INVALID_DISPLAY
- ? mCurTokenDisplayId : DEFAULT_DISPLAY);
+ .hasNavigationBar(tokenDisplayId != INVALID_DISPLAY
+ ? tokenDisplayId : DEFAULT_DISPLAY);
final boolean canImeDrawsImeNavBar =
mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get() && hasNavigationBar;
final boolean shouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherLocked(
@@ -2764,8 +2828,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// Note that we still need to update IME status when focusing external display
// that does not support system decoration and fallback to show IME on default
// display since it is intentional behavior.
- if (mCurTokenDisplayId != topFocusedDisplayId
- && mCurTokenDisplayId != FALLBACK_DISPLAY_ID) {
+ final int tokenDisplayId = getCurTokenDisplayIdLocked();
+ if (tokenDisplayId != topFocusedDisplayId && tokenDisplayId != FALLBACK_DISPLAY_ID) {
return;
}
mImeWindowVis = vis;
@@ -2828,7 +2892,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
Slog.d(TAG, "IME window vis: " + vis
+ " active: " + (vis & InputMethodService.IME_ACTIVE)
+ " inv: " + (vis & InputMethodService.IME_INVISIBLE)
- + " displayId: " + mCurTokenDisplayId);
+ + " displayId: " + getCurTokenDisplayIdLocked());
}
final IBinder focusedWindowToken = mImeBindingState != null
? mImeBindingState.mFocusedWindow : null;
@@ -2857,7 +2921,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
if (mStatusBarManagerInternal != null) {
- mStatusBarManagerInternal.setImeWindowStatus(mCurTokenDisplayId,
+ mStatusBarManagerInternal.setImeWindowStatus(getCurTokenDisplayIdLocked(),
getCurTokenLocked(), vis, backDisposition, needsToShowImeSwitcher);
}
} finally {
@@ -2871,6 +2935,49 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mMenuController.updateKeyboardFromSettingsLocked();
}
+ /**
+ * This is an experimental implementation used when and only when
+ * {@link #mExperimentalConcurrentMultiUserModeEnabled}.
+ *
+ * <p>Never assume what this method is doing is officially supported. For the canonical and
+ * desired behaviors always refer to single-user code paths such as
+ * {@link #updateInputMethodsFromSettingsLocked(boolean)}.</p>
+ *
+ * <p>Here are examples of missing features.</p>
+ * <ul>
+ * <li>Subtypes are not supported at all!</li>
+ * <li>Profiles are not supported.</li>
+ * <li>
+ * {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED} is not updated.
+ * </li>
+ * <li>{@link #mDeviceIdToShowIme} is ignored.</li>
+ * <li>{@link #mSwitchingController} is ignored.</li>
+ * <li>{@link #mHardwareKeyboardShortcutController} is ignored.</li>
+ * <li>{@link #mPreventImeStartupUnlessTextEditor} is ignored.</li>
+ * <li>and so on.</li>
+ * </ul>
+ */
+ @GuardedBy("ImfLock.class")
+ void experimentalInitializeVisibleBackgroundUserLocked(@UserIdInt int userId) {
+ if (!mUserManagerInternal.isUserVisible(userId)) {
+ return;
+ }
+ final var settings = InputMethodSettingsRepository.get(userId);
+ String id = settings.getSelectedInputMethod();
+ if (TextUtils.isEmpty(id)) {
+ final InputMethodInfo imi = InputMethodInfoUtils.getMostApplicableDefaultIME(
+ settings.getEnabledInputMethodList());
+ if (imi == null) {
+ return;
+ }
+ id = imi.getId();
+ settings.putSelectedInputMethod(id);
+ }
+ final var userData = mUserDataRepository.getOrCreate(userId);
+ final var bindingController = userData.mBindingController;
+ bindingController.setSelectedMethodId(id);
+ }
+
@GuardedBy("ImfLock.class")
void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
@@ -3546,13 +3653,14 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final InputBindResult result;
synchronized (ImfLock.class) {
final var userData = mUserDataRepository.getOrCreate(userId);
+ final var bindingController = userData.mBindingController;
// If the system is not yet ready, we shouldn't be running third party code.
if (!mSystemReady) {
return new InputBindResult(
InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
null /* method */, null /* accessibilitySessions */, null /* channel */,
getSelectedMethodIdLocked(),
- userData.mBindingController.getSequenceNumber(),
+ bindingController.getSequenceNumber(),
false /* isInputMethodSuppressingSpellChecker */);
}
final ClientState cs = mClientController.getClient(client.asBinder());
@@ -3761,7 +3869,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// window token removed.
// Note that we can trust client's display ID as long as it matches
// to the display ID obtained from the window.
- if (cs.mSelfReportedDisplayId != mCurTokenDisplayId) {
+ if (cs.mSelfReportedDisplayId != getCurTokenDisplayIdLocked()) {
userData.mBindingController.unbindCurrentMethod();
}
}
@@ -4125,7 +4233,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
* This is kept due to {@code @UnsupportedAppUsage} in
* {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
* {@link InputMethodService#onCreate()}.
- *
* @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight(int)}
*
* @deprecated TODO(b/113914148): Check if we can remove this
@@ -4143,7 +4250,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
// This should probably use the caller's display id, but because this is unsupported
// and maintained only for compatibility, there's no point in fixing it.
- curTokenDisplayId = mCurTokenDisplayId;
+ curTokenDisplayId = getCurTokenDisplayIdLocked();
}
return mWindowManagerInternal.getInputMethodWindowVisibleHeight(curTokenDisplayId);
});
@@ -4224,8 +4331,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// a new Stylus is detected. If IME supports handwriting, and we don't have
// handwriting initialized, lets do it now.
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ final var bindingController = userData.mBindingController;
if (!mHwController.getCurrentRequestId().isPresent()
- && userData.mBindingController.supportsStylusHandwriting()) {
+ && bindingController.supportsStylusHandwriting()) {
scheduleResetStylusHandwriting();
}
}
@@ -4283,7 +4391,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Helper method to set a stylus idle-timeout after which handwriting {@code InkWindow}
* will be removed.
- * @param timeout to set in milliseconds. To reset to default, use a value <= zero.
+ *
+ * @param timeout to set in milliseconds. To reset to default, use a value <= zero
*/
@BinderThread
@IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)
@@ -4407,9 +4516,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private void dumpDebug(ProtoOutputStream proto, long fieldId) {
synchronized (ImfLock.class) {
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ final var bindingController = userData.mBindingController;
final long token = proto.start(fieldId);
proto.write(CUR_METHOD_ID, getSelectedMethodIdLocked());
- proto.write(CUR_SEQ, userData.mBindingController.getSequenceNumber());
+ proto.write(CUR_SEQ, bindingController.getSequenceNumber());
proto.write(CUR_CLIENT, Objects.toString(mCurClient));
mImeBindingState.dumpDebug(proto, mWindowManagerInternal);
proto.write(LAST_IME_TARGET_WINDOW_NAME,
@@ -4419,13 +4529,13 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
if (mCurEditorInfo != null) {
mCurEditorInfo.dumpDebug(proto, CUR_ATTRIBUTE);
}
- proto.write(CUR_ID, userData.mBindingController.getCurId());
+ proto.write(CUR_ID, bindingController.getCurId());
mVisibilityStateComputer.dumpDebug(proto, fieldId);
proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked()));
- proto.write(CUR_TOKEN_DISPLAY_ID, mCurTokenDisplayId);
+ proto.write(CUR_TOKEN_DISPLAY_ID, getCurTokenDisplayIdLocked());
proto.write(SYSTEM_READY, mSystemReady);
- proto.write(HAVE_CONNECTION, userData.mBindingController.hasMainConnection());
+ proto.write(HAVE_CONNECTION, bindingController.hasMainConnection());
proto.write(BOUND_TO_METHOD, mBoundToMethod);
proto.write(IS_INTERACTIVE, mIsInteractive);
proto.write(BACK_DISPOSITION, mBackDisposition);
@@ -4537,7 +4647,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final IBinder requestToken = mVisibilityStateComputer.getWindowTokenFrom(requestImeToken);
final WindowManagerInternal.ImeTargetInfo info =
mWindowManagerInternal.onToggleImeRequested(
- show, mImeBindingState.mFocusedWindow, requestToken, mCurTokenDisplayId);
+ show, mImeBindingState.mFocusedWindow, requestToken,
+ getCurTokenDisplayIdLocked());
mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
mImeBindingState.mFocusedWindowClient, mImeBindingState.mFocusedWindowEditorInfo,
info.focusedWindowName, mImeBindingState.mFocusedWindowSoftInputMode, reason,
@@ -4796,10 +4907,11 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
case MSG_RESET_HANDWRITING: {
synchronized (ImfLock.class) {
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- if (userData.mBindingController.supportsStylusHandwriting()
+ final var bindingController = userData.mBindingController;
+ if (bindingController.supportsStylusHandwriting()
&& getCurMethodLocked() != null && hasSupportedStylusLocked()) {
Slog.d(TAG, "Initializing Handwriting Spy");
- mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
+ mHwController.initializeHandwritingSpy(getCurTokenDisplayIdLocked());
} else {
mHwController.reset();
}
@@ -4822,11 +4934,12 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
return true;
}
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ final var bindingController = userData.mBindingController;
final HandwritingModeController.HandwritingSession session =
mHwController.startHandwritingSession(
msg.arg1 /*requestId*/,
msg.arg2 /*pid*/,
- userData.mBindingController.getCurMethodUid(),
+ bindingController.getCurMethodUid(),
mImeBindingState.mFocusedWindow);
if (session == null) {
Slog.e(TAG,
@@ -4878,8 +4991,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
// TODO(b/325515685): user data must be retrieved by a userId parameter
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ final var bindingController = userData.mBindingController;
if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(
- userData.mBindingController.getCurMethodUid())) {
+ bindingController.getCurMethodUid())) {
// Handle IME visibility when interactive changed before finishing the input to
// ensure we preserve the last state as possible.
final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.onInteractiveChanged(
@@ -5124,7 +5238,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@GuardedBy("ImfLock.class")
void sendOnNavButtonFlagsChangedLocked() {
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final IInputMethodInvoker curMethod = userData.mBindingController.getCurMethod();
+ final var bindingController = userData.mBindingController;
+ final IInputMethodInvoker curMethod = bindingController.getCurMethod();
if (curMethod == null) {
// No need to send the data if the IME is not yet bound.
return;
@@ -5169,10 +5284,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Enable or disable the given IME by updating {@link Settings.Secure#ENABLED_INPUT_METHODS}.
*
- * @param id ID of the IME is to be manipulated. It is OK to pass IME ID that is currently not
- * recognized by the system.
- * @param enabled {@code true} if {@code id} needs to be enabled.
- * @return {@code true} if the IME was previously enabled. {@code false} otherwise.
+ * @param id ID of the IME is to be manipulated. It is OK to pass IME ID that is currently
+ * not recognized by the system
+ * @param enabled {@code true} if {@code id} needs to be enabled
+ * @return {@code true} if the IME was previously enabled
*/
@GuardedBy("ImfLock.class")
private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
@@ -5279,8 +5394,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Gets the current subtype of this input method.
*
- * @param userId User ID to be queried about.
- * @return The current {@link InputMethodSubtype} for the specified user.
+ * @param userId User ID to be queried about
+ * @return the current {@link InputMethodSubtype} for the specified user
*/
@Nullable
@Override
@@ -5354,7 +5469,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Returns the default {@link InputMethodInfo} for the specific userId.
- * @param userId user ID to query.
+ *
+ * @param userId user ID to query
*/
@GuardedBy("ImfLock.class")
private InputMethodInfo queryDefaultInputMethodForUserIdLocked(@UserIdInt int userId) {
@@ -5388,11 +5504,11 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
* Filter the access to the input method by rules of the package visibility. Return {@code true}
* if the given input method is the currently selected one or visible to the caller.
*
- * @param targetPkgName The package name of input method to check.
- * @param callingUid The caller that is going to access the input method.
- * @param userId The user ID where the input method resides.
- * @param settings The input method settings under the given user ID.
- * @return {@code true} if caller is able to access the input method.
+ * @param targetPkgName the package name of input method to check
+ * @param callingUid the caller that is going to access the input method
+ * @param userId the user ID where the input method resides
+ * @param settings the input method settings under the given user ID
+ * @return {@code true} if caller is able to access the input method
*/
private boolean canCallerAccessInputMethod(@NonNull String targetPkgName, int callingUid,
@UserIdInt int userId, @NonNull InputMethodSettings settings) {
@@ -5558,7 +5674,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
//TODO(b/150843766): Check if Input Token is valid.
final IBinder curHostInputToken;
synchronized (ImfLock.class) {
- if (displayId != mCurTokenDisplayId) {
+ if (displayId != getCurTokenDisplayIdLocked()) {
return false;
}
curHostInputToken = mAutofillController.getCurHostInputToken();
@@ -5610,6 +5726,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
IAccessibilityInputMethodSession session, @UserIdInt int userId) {
synchronized (ImfLock.class) {
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ final var bindingController = userData.mBindingController;
// TODO(b/305829876): Implement user ID verification
if (mCurClient != null) {
clearClientSessionForAccessibilityLocked(mCurClient, accessibilityConnectionId);
@@ -5632,8 +5749,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final InputBindResult res = new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION,
imeSession, accessibilityInputMethodSessions, /* channel= */ null,
- userData.mBindingController.getCurId(),
- userData.mBindingController.getSequenceNumber(),
+ bindingController.getCurId(),
+ bindingController.getSequenceNumber(),
/* isInputMethodSuppressingSpellChecker= */ false);
mCurClient.mClient.onBindAccessibilityService(res, accessibilityConnectionId);
}
@@ -5645,6 +5762,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@UserIdInt int userId) {
synchronized (ImfLock.class) {
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ final var bindingController = userData.mBindingController;
// TODO(b/305829876): Implement user ID verification
if (mCurClient != null) {
if (DEBUG) {
@@ -5654,7 +5772,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// A11yManagerService unbinds the disabled accessibility service. We don't need
// to do it here.
mCurClient.mClient.onUnbindAccessibilityService(
- userData.mBindingController.getSequenceNumber(),
+ bindingController.getSequenceNumber(),
accessibilityConnectionId);
}
// We only have sessions when we bound to an input method. Remove this session
@@ -5877,18 +5995,19 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
};
mClientController.forAllClients(clientControllerDump);
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ final var bindingController = userData.mBindingController;
p.println(" mCurrentUserId=" + mCurrentUserId);
p.println(" mCurMethodId=" + getSelectedMethodIdLocked());
client = mCurClient;
p.println(" mCurClient=" + client + " mCurSeq="
- + userData.mBindingController.getSequenceNumber());
+ + bindingController.getSequenceNumber());
p.println(" mFocusedWindowPerceptible=" + mFocusedWindowPerceptible);
mImeBindingState.dump(/* prefix= */ " ", p);
- p.println(" mCurId=" + userData.mBindingController.getCurId()
- + " mHaveConnection=" + userData.mBindingController.hasMainConnection()
+ p.println(" mCurId=" + bindingController.getCurId()
+ + " mHaveConnection=" + bindingController.hasMainConnection()
+ " mBoundToMethod=" + mBoundToMethod + " mVisibleBound="
- + userData.mBindingController.isVisibleBound());
+ + bindingController.isVisibleBound());
p.println(" mUserDataRepository=");
// TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
@@ -5902,15 +6021,17 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mUserDataRepository.forAllUserData(userDataDump);
p.println(" mCurToken=" + getCurTokenLocked());
- p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
+ p.println(" mCurTokenDisplayId=" + getCurTokenDisplayIdLocked());
p.println(" mCurHostInputToken=" + mAutofillController.getCurHostInputToken());
- p.println(" mCurIntent=" + userData.mBindingController.getCurIntent());
+ p.println(" mCurIntent=" + bindingController.getCurIntent());
method = getCurMethodLocked();
p.println(" mCurMethod=" + getCurMethodLocked());
p.println(" mEnabledSession=" + mEnabledSession);
mVisibilityStateComputer.dump(pw, " ");
p.println(" mInFullscreenMode=" + mInFullscreenMode);
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
+ p.println(" mExperimentalConcurrentMultiUserModeEnabled="
+ + mExperimentalConcurrentMultiUserModeEnabled);
p.println(" ENABLE_HIDE_IME_CAPTION_BAR="
+ InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR);
p.println(" mSettingsObserver=" + mSettingsObserver);
@@ -6143,8 +6264,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Handles {@code adb shell ime list}.
- * @param shellCommand {@link ShellCommand} object that is handling this command.
- * @return Exit code of the command.
+ *
+ * @param shellCommand {@link ShellCommand} object that is handling this command
+ * @return exit code of the command
*/
@BinderThread
@ShellCommandResult
@@ -6202,9 +6324,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Handles {@code adb shell ime enable} and {@code adb shell ime disable}.
*
- * @param shellCommand {@link ShellCommand} object that is handling this command.
- * @param enabled {@code true} if the command was {@code adb shell ime enable}.
- * @return Exit code of the command.
+ * @param shellCommand {@link ShellCommand} object that is handling this command
+ * @param enabled {@code true} if the command was {@code adb shell ime enable}
+ * @return exit code of the command
*/
@BinderThread
@ShellCommandResult
@@ -6239,8 +6361,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
* {@link ShellCommand#getNextArg()} and {@link ShellCommand#getNextArgRequired()} for the
* main arguments.</p>
*
- * @param shellCommand {@link ShellCommand} from which options should be obtained.
- * @return User ID to be resolved. {@link UserHandle#CURRENT} if not specified.
+ * @param shellCommand {@link ShellCommand} from which options should be obtained
+ * @return user ID to be resolved. {@link UserHandle#CURRENT} if not specified
*/
@BinderThread
@UserIdInt
@@ -6262,12 +6384,12 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Handles core logic of {@code adb shell ime enable} and {@code adb shell ime disable}.
*
- * @param userId user ID specified to the command. Pseudo user IDs are not supported.
- * @param imeId IME ID specified to the command.
- * @param enabled {@code true} for {@code adb shell ime enable}. {@code false} otherwise.
- * @param out {@link PrintWriter} to output standard messages.
- * @param error {@link PrintWriter} to output error messages.
- * @return {@code false} if it fails to enable the IME. {@code false} otherwise.
+ * @param userId user ID specified to the command (pseudo user IDs are not supported)
+ * @param imeId IME ID specified to the command
+ * @param enabled {@code true} for {@code adb shell ime enable}
+ * @param out {@link PrintWriter} to output standard messages
+ * @param error {@link PrintWriter} to output error messages
+ * @return {@code false} if it fails to enable the IME
*/
@BinderThread
@GuardedBy("ImfLock.class")
@@ -6325,7 +6447,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Handles {@code adb shell ime set}.
*
- * @param shellCommand {@link ShellCommand} object that is handling this command.
+ * @param shellCommand {@link ShellCommand} object that is handling this command
* @return Exit code of the command.
*/
@BinderThread
@@ -6368,7 +6490,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Handles {@code adb shell ime reset-ime}.
- * @param shellCommand {@link ShellCommand} object that is handling this command.
+ *
+ * @param shellCommand {@link ShellCommand} object that is handling this command
* @return Exit code of the command.
*/
@BinderThread
@@ -6384,8 +6507,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
continue;
}
// Skip on headless user
- if (USER_TYPE_SYSTEM_HEADLESS.equals(
- mUserManagerInternal.getUserInfo(userId).userType)) {
+ final var userInfo = mUserManagerInternal.getUserInfo(userId);
+ if (userInfo != null && USER_TYPE_SYSTEM_HEADLESS.equals(userInfo.userType)) {
continue;
}
final String nextIme;
@@ -6395,7 +6518,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
final var userData = mUserDataRepository.getOrCreate(userId);
- userData.mBindingController.unbindCurrentMethod();
+ final var bindingController = userData.mBindingController;
+ bindingController.unbindCurrentMethod();
// Enable default IMEs, disable others
var toDisable = settings.getEnabledInputMethodList();
@@ -6448,7 +6572,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Handles {@code adb shell cmd input_method tracing start/stop/save-for-bugreport}.
- * @param shellCommand {@link ShellCommand} object that is handling this command.
+ *
+ * @param shellCommand {@link ShellCommand} object that is handling this command
* @return Exit code of the command.
*/
@BinderThread
@@ -6493,9 +6618,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
- * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
- * @return {@code true} if userId has debugging privileges.
- * i.e. {@link UserManager#DISALLOW_DEBUGGING_FEATURES} is {@code false}.
+ * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}
+ * @return {@code true} if userId has debugging privileges
+ * i.e. {@link UserManager#DISALLOW_DEBUGGING_FEATURES} is {@code false}
*/
private boolean userHasDebugPriv(@UserIdInt int userId, ShellCommand shellCommand) {
if (mUserManagerInternal.hasUserRestriction(
@@ -6516,8 +6641,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
/**
* Creates an IME request tracking token for the current focused client.
*
- * @param show whether this is a show or a hide request.
- * @param reason the reason why the IME request was created.
+ * @param show whether this is a show or a hide request
+ * @param reason the reason why the IME request was created
*/
@NonNull
private ImeTracker.Token createStatsTokenForFocusedClient(boolean show,
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMap.java b/services/core/java/com/android/server/inputmethod/InputMethodMap.java
index 221309e4bf3e..bab21e8b7b06 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMap.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMap.java
@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.util.ArrayMap;
import android.view.inputmethod.InputMethodInfo;
+import java.util.Arrays;
import java.util.List;
/**
@@ -99,4 +100,37 @@ final class InputMethodMap {
}
return updated ? InputMethodMap.of(newMethodMap) : this;
}
+
+ /**
+ * Compares the given two {@link InputMethodMap} instances to see if they contain the same data
+ * or not.
+ *
+ * @param map1 {@link InputMethodMap} to be compared with
+ * @param map2 {@link InputMethodMap} to be compared with
+ * @return {@code true} if both {@link InputMethodMap} instances contain exactly the same data
+ */
+ @AnyThread
+ static boolean areSame(@NonNull InputMethodMap map1, @NonNull InputMethodMap map2) {
+ if (map1 == map2) {
+ return true;
+ }
+ final int size = map1.size();
+ if (size != map2.size()) {
+ return false;
+ }
+ for (int i = 0; i < size; ++i) {
+ final var imi1 = map1.valueAt(i);
+ final var imeId = imi1.getId();
+ final var imi2 = map2.get(imeId);
+ if (imi2 == null) {
+ return false;
+ }
+ final var marshaled1 = InputMethodInfoUtils.marshal(imi1);
+ final var marshaled2 = InputMethodInfoUtils.marshal(imi2);
+ if (!Arrays.equals(marshaled1, marshaled2)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 73647dbbe978..e1f893953d66 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -2800,6 +2800,10 @@ class MediaRouter2ServiceImpl {
final String providerId = route.getProviderId();
final MediaRoute2Provider provider = findProvider(providerId);
if (provider == null) {
+ Slog.w(
+ TAG,
+ "Ignoring transferToRoute due to lack of matching provider for target: "
+ + route);
return;
}
provider.transferToRoute(
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index a3c5d2d336f2..69f07d5c5f7b 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -1057,6 +1057,7 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde
return -1;
}
+ @NonNull
private PlaybackInfo getVolumeAttributes() {
int volumeType;
AudioAttributes attributes;
@@ -1850,6 +1851,7 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde
return mFlags;
}
+ @NonNull
@Override
public PlaybackInfo getVolumeAttributes() {
return MediaSessionRecord.this.getVolumeAttributes();
diff --git a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
index a78b3a2e0c61..13429db47ebd 100644
--- a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
+++ b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
@@ -22,12 +22,14 @@ import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import static android.media.audio.Flags.focusExclusiveWithRecording;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
+import android.Manifest.permission;
import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.KeyguardManager;
@@ -223,7 +225,10 @@ public final class NotificationAttentionHelper {
mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T2),
mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1),
mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2),
- mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET));
+ mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET),
+ record -> mPackageManager.checkPermission(
+ permission.RECEIVE_EMERGENCY_BROADCAST,
+ record.getSbn().getPackageName()) == PERMISSION_GRANTED);
return new StrategyAvalanche(
mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T1),
@@ -231,14 +236,17 @@ public final class NotificationAttentionHelper {
mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1),
mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2),
mFlagResolver.getIntValue(NotificationFlags.NOTIF_AVALANCHE_TIMEOUT),
- appStrategy);
+ appStrategy, appStrategy.mExemptionProvider);
} else {
return new StrategyPerApp(
mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T1),
mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T2),
mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1),
mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2),
- mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET));
+ mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET),
+ record -> mPackageManager.checkPermission(
+ permission.RECEIVE_EMERGENCY_BROADCAST,
+ record.getSbn().getPackageName()) == PERMISSION_GRANTED);
}
}
@@ -1098,6 +1106,11 @@ public final class NotificationAttentionHelper {
}
}
+ // Returns true if a notification should be exempted from attenuation
+ private interface ExemptionProvider {
+ boolean isExempted(NotificationRecord record);
+ }
+
@VisibleForTesting
abstract static class PolitenessStrategy {
static final int POLITE_STATE_DEFAULT = 0;
@@ -1128,8 +1141,10 @@ public final class NotificationAttentionHelper {
protected boolean mIsActive = true;
+ protected final ExemptionProvider mExemptionProvider;
+
public PolitenessStrategy(int timeoutPolite, int timeoutMuted, int volumePolite,
- int volumeMuted) {
+ int volumeMuted, ExemptionProvider exemptionProvider) {
mVolumeStates = new HashMap<>();
mLastUpdatedTimestampByPackage = new HashMap<>();
@@ -1137,6 +1152,7 @@ public final class NotificationAttentionHelper {
this.mTimeoutMuted = timeoutMuted;
this.mVolumePolite = volumePolite / 100.0f;
this.mVolumeMuted = volumeMuted / 100.0f;
+ this.mExemptionProvider = exemptionProvider;
}
abstract void onNotificationPosted(NotificationRecord record);
@@ -1294,8 +1310,8 @@ public final class NotificationAttentionHelper {
private final int mMaxPostedForReset;
public StrategyPerApp(int timeoutPolite, int timeoutMuted, int volumePolite,
- int volumeMuted, int maxPosted) {
- super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted);
+ int volumeMuted, int maxPosted, ExemptionProvider exemptionProvider) {
+ super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted, exemptionProvider);
mNumPosted = new HashMap<>();
mMaxPostedForReset = maxPosted;
@@ -1316,7 +1332,12 @@ public final class NotificationAttentionHelper {
final String key = getChannelKey(record);
@PolitenessState final int currState = getPolitenessState(record);
- @PolitenessState int nextState = getNextState(currState, timeSinceLastNotif);
+ @PolitenessState int nextState;
+ if (Flags.politeNotificationsAttnUpdate()) {
+ nextState = getNextState(currState, timeSinceLastNotif, record);
+ } else {
+ nextState = getNextState(currState, timeSinceLastNotif);
+ }
// Reset to default state if number of posted notifications exceed this value when muted
int numPosted = mNumPosted.getOrDefault(key, 0) + 1;
@@ -1334,6 +1355,14 @@ public final class NotificationAttentionHelper {
mVolumeStates.put(key, nextState);
}
+ @PolitenessState int getNextState(@PolitenessState final int currState,
+ final long timeSinceLastNotif, final NotificationRecord record) {
+ if (mExemptionProvider.isExempted(record)) {
+ return POLITE_STATE_DEFAULT;
+ }
+ return getNextState(currState, timeSinceLastNotif);
+ }
+
@Override
public void onUserInteraction(final NotificationRecord record) {
super.onUserInteraction(record);
@@ -1354,8 +1383,9 @@ public final class NotificationAttentionHelper {
private long mLastAvalancheTriggerTimestamp = 0;
StrategyAvalanche(int timeoutPolite, int timeoutMuted, int volumePolite,
- int volumeMuted, int timeoutAvalanche, PolitenessStrategy appStrategy) {
- super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted);
+ int volumeMuted, int timeoutAvalanche, PolitenessStrategy appStrategy,
+ ExemptionProvider exemptionProvider) {
+ super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted, exemptionProvider);
mTimeoutAvalanche = timeoutAvalanche;
mAppStrategy = appStrategy;
@@ -1528,7 +1558,7 @@ public final class NotificationAttentionHelper {
return true;
}
- return false;
+ return mExemptionProvider.isExempted(record);
}
private boolean isAvalancheExempted(final NotificationRecord record) {
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index b2e861cf2876..cdc1a5e738a0 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.ondeviceintelligence;
+import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.DEVICE_CONFIG_UPDATE_BUNDLE_KEY;
import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_LOADED_BUNDLE_KEY;
import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_UNLOADED_BUNDLE_KEY;
import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.REGISTER_MODEL_UPDATE_CALLBACK_BUNDLE_KEY;
@@ -115,9 +116,10 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
/** Handler message to {@link #resetTemporaryServices()} */
private static final int MSG_RESET_TEMPORARY_SERVICE = 0;
-
/** Handler message to clean up temporary broadcast keys. */
private static final int MSG_RESET_BROADCAST_KEYS = 1;
+ /** Handler message to clean up temporary config namespace. */
+ private static final int MSG_RESET_CONFIG_NAMESPACE = 2;
/** Default value in absence of {@link DeviceConfig} override. */
private static final boolean DEFAULT_SERVICE_ENABLED = true;
@@ -129,6 +131,7 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
private final Executor resourceClosingExecutor = Executors.newCachedThreadPool();
private final Executor callbackExecutor = Executors.newCachedThreadPool();
private final Executor broadcastExecutor = Executors.newCachedThreadPool();
+ private final Executor mConfigExecutor = Executors.newCachedThreadPool();
private final Context mContext;
@@ -145,6 +148,12 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
private String[] mTemporaryBroadcastKeys;
@GuardedBy("mLock")
private String mBroadcastPackageName;
+ @GuardedBy("mLock")
+ private String mTemporaryConfigNamespace;
+
+ private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
+ this::sendUpdatedConfig;
+
/**
* Handler used to reset the temporary service names.
@@ -593,12 +602,14 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
@NonNull IOnDeviceSandboxedInferenceService service) {
try {
ensureRemoteIntelligenceServiceInitialized();
+ service.registerRemoteStorageService(
+ getIRemoteStorageService());
mRemoteOnDeviceIntelligenceService.run(
IOnDeviceIntelligenceService::notifyInferenceServiceConnected);
broadcastExecutor.execute(
() -> registerModelLoadingBroadcasts(service));
- service.registerRemoteStorageService(
- getIRemoteStorageService());
+ mConfigExecutor.execute(
+ () -> registerDeviceConfigChangeListener());
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to send connected event", ex);
}
@@ -658,6 +669,58 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
}
+ private void registerDeviceConfigChangeListener() {
+ Log.e(TAG, "registerDeviceConfigChangeListener");
+ String configNamespace = getConfigNamespace();
+ if (configNamespace.isEmpty()) {
+ Slog.e(TAG, "config_defaultOnDeviceIntelligenceDeviceConfigNamespace is empty");
+ return;
+ }
+ DeviceConfig.addOnPropertiesChangedListener(
+ configNamespace,
+ mConfigExecutor,
+ mOnPropertiesChangedListener);
+ }
+
+ private String getConfigNamespace() {
+ synchronized (mLock) {
+ if (mTemporaryConfigNamespace != null) {
+ return mTemporaryConfigNamespace;
+ }
+
+ return mContext.getResources().getString(
+ R.string.config_defaultOnDeviceIntelligenceDeviceConfigNamespace);
+ }
+ }
+
+ private void sendUpdatedConfig(
+ DeviceConfig.Properties props) {
+ Log.e(TAG, "sendUpdatedConfig");
+
+ PersistableBundle persistableBundle = new PersistableBundle();
+ for (String key : props.getKeyset()) {
+ persistableBundle.putString(key, props.getString(key, ""));
+ }
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(DEVICE_CONFIG_UPDATE_BUNDLE_KEY, persistableBundle);
+ ensureRemoteInferenceServiceInitialized();
+ Log.e(TAG, "sendUpdatedConfig: BUNDLE: " + bundle);
+
+ mRemoteInferenceService.run(service -> service.updateProcessingState(bundle,
+ new IProcessingUpdateStatusCallback.Stub() {
+ @Override
+ public void onSuccess(PersistableBundle result) {
+ Slog.d(TAG, "Config update successful." + result);
+ }
+
+ @Override
+ public void onFailure(int errorCode, String errorMessage) {
+ Slog.e(TAG, "Config update failed with code ["
+ + String.valueOf(errorCode) + "] and message = " + errorMessage);
+ }
+ }));
+ }
+
@NonNull
private IRemoteStorageService.Stub getIRemoteStorageService() {
return new IRemoteStorageService.Stub() {
@@ -849,8 +912,23 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
@RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+ public void setTemporaryDeviceConfigNamespace(@NonNull String configNamespace,
+ int durationMs) {
+ Objects.requireNonNull(configNamespace);
+ enforceShellOnly(Binder.getCallingUid(), "setTemporaryDeviceConfigNamespace");
+ mContext.enforceCallingPermission(
+ Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+ synchronized (mLock) {
+ mTemporaryConfigNamespace = configNamespace;
+ if (durationMs != -1) {
+ getTemporaryHandler().sendEmptyMessageDelayed(MSG_RESET_CONFIG_NAMESPACE,
+ durationMs);
+ }
+ }
+ }
+
+ @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
public void resetTemporaryServices() {
- enforceShellOnly(Binder.getCallingUid(), "resetTemporaryServices");
mContext.enforceCallingPermission(
Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
synchronized (mLock) {
@@ -937,17 +1015,17 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) {
@Override
public void handleMessage(Message msg) {
- if (msg.what == MSG_RESET_TEMPORARY_SERVICE) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (msg.what == MSG_RESET_TEMPORARY_SERVICE) {
resetTemporaryServices();
- }
- } else if (msg.what == MSG_RESET_BROADCAST_KEYS) {
- synchronized (mLock) {
+ } else if (msg.what == MSG_RESET_BROADCAST_KEYS) {
mTemporaryBroadcastKeys = null;
mBroadcastPackageName = SYSTEM_PACKAGE;
+ } else if (msg.what == MSG_RESET_CONFIG_NAMESPACE) {
+ mTemporaryConfigNamespace = null;
+ } else {
+ Slog.wtf(TAG, "invalid handler msg: " + msg);
}
- } else {
- Slog.wtf(TAG, "invalid handler msg: " + msg);
}
}
};
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java
index 5744b5c3c2c4..d2c84fa1b18a 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java
@@ -17,6 +17,7 @@
package com.android.server.ondeviceintelligence;
import android.annotation.NonNull;
+import android.os.Binder;
import android.os.ShellCommand;
import java.io.PrintWriter;
@@ -45,6 +46,8 @@ final class OnDeviceIntelligenceShellCommand extends ShellCommand {
return getConfiguredServices();
case "set-model-broadcasts":
return setBroadcastKeys();
+ case "set-deviceconfig-namespace":
+ return setDeviceConfigNamespace();
default:
return handleDefaultCommands(cmd);
}
@@ -69,6 +72,10 @@ final class OnDeviceIntelligenceShellCommand extends ShellCommand {
+ "[ReceiverPackageName] "
+ "[DURATION] To set the names of broadcast intent keys that are to be "
+ "emitted for cts tests.");
+ pw.println(
+ " set-deviceconfig-namespace [DeviceConfigNamespace] "
+ + "[DURATION] To set the device config namespace "
+ + "to use for cts tests.");
}
private int setTemporaryServices() {
@@ -78,6 +85,8 @@ final class OnDeviceIntelligenceShellCommand extends ShellCommand {
if (getRemainingArgsCount() == 0 && intelligenceServiceName == null
&& inferenceServiceName == null) {
+ OnDeviceIntelligenceManagerService.enforceShellOnly(Binder.getCallingUid(),
+ "resetTemporaryServices");
mService.resetTemporaryServices();
out.println("OnDeviceIntelligenceManagerService temporary reset. ");
return 0;
@@ -120,4 +129,16 @@ final class OnDeviceIntelligenceShellCommand extends ShellCommand {
return 0;
}
+ private int setDeviceConfigNamespace() {
+ final PrintWriter out = getOutPrintWriter();
+ final String configNamespace = getNextArg();
+
+ final int duration = Integer.parseInt(getNextArgRequired());
+ mService.setTemporaryDeviceConfigNamespace(configNamespace, duration);
+ out.println("OnDeviceIntelligence DeviceConfig Namespace temporarily set to "
+ + configNamespace
+ + " for " + duration + "ms");
+ return 0;
+ }
+
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 908b47df35e1..472f228b689f 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -37,7 +37,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_UID_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
-import static android.content.pm.PackageManager.PROPERTY_ANDROID_SAFETY_LABEL_PATH;
+import static android.content.pm.PackageManager.PROPERTY_ANDROID_SAFETY_LABEL;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
@@ -505,6 +505,7 @@ final class InstallPackageHelper {
// metadata file path for the new package.
if (oldPkgSetting != null) {
pkgSetting.setAppMetadataFilePath(null);
+ pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_UNKNOWN);
}
// If the app metadata file path is not null then this is a system app with a preloaded app
// metadata file on the system image. Do not reset the path and source if this is the
@@ -523,7 +524,7 @@ final class InstallPackageHelper {
}
} else if (Flags.aslInApkAppMetadataSource()) {
Map<String, PackageManager.Property> properties = pkg.getProperties();
- if (properties.containsKey(PROPERTY_ANDROID_SAFETY_LABEL_PATH)) {
+ if (properties.containsKey(PROPERTY_ANDROID_SAFETY_LABEL)) {
// ASL file extraction is done in post-install
pkgSetting.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_APK);
diff --git a/services/core/java/com/android/server/pm/PackageFreezer.java b/services/core/java/com/android/server/pm/PackageFreezer.java
index 7c5615771607..0afda4598bcb 100644
--- a/services/core/java/com/android/server/pm/PackageFreezer.java
+++ b/services/core/java/com/android/server/pm/PackageFreezer.java
@@ -18,6 +18,7 @@ package com.android.server.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.Flags;
import android.content.pm.PackageManager;
import dalvik.system.CloseGuard;
@@ -76,8 +77,13 @@ final class PackageFreezer implements AutoCloseable {
ps = mPm.mSettings.getPackageLPr(mPackageName);
}
if (ps != null) {
- mPm.killApplication(ps.getPackageName(), ps.getAppId(), userId, killReason,
- exitInfoReason);
+ if (Flags.waitApplicationKilled()) {
+ mPm.killApplicationSync(ps.getPackageName(), ps.getAppId(), userId, killReason,
+ exitInfoReason);
+ } else {
+ mPm.killApplication(ps.getPackageName(), ps.getAppId(), userId, killReason,
+ exitInfoReason);
+ }
}
mCloseGuard.open("close");
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 121cf3f231b0..f8fceda0582c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -53,6 +53,7 @@ import android.annotation.StringRes;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.ApplicationExitInfo;
import android.app.ApplicationPackageManager;
@@ -3132,6 +3133,20 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
}
+ void killApplicationSync(String pkgName, @AppIdInt int appId,
+ @UserIdInt int userId, String reason, int exitInfoReason) {
+ ActivityManagerInternal mAmi = LocalServices.getService(ActivityManagerInternal.class);
+ if (mAmi != null) {
+ if (Thread.holdsLock(mLock)) {
+ // holds PM's lock, go back killApplication to avoid it run into watchdog reset.
+ Slog.e(TAG, "Holds PM's locker, unable kill application synchronized");
+ killApplication(pkgName, appId, userId, reason, exitInfoReason);
+ } else {
+ mAmi.killApplicationSync(pkgName, appId, userId, reason, exitInfoReason);
+ }
+ }
+ }
+
@Override
public void notifyPackageAdded(String packageName, int uid) {
mPackageObserverHelper.notifyAdded(packageName, uid);
@@ -4003,7 +4018,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final PackageMetrics.ComponentStateMetrics componentStateMetrics =
new PackageMetrics.ComponentStateMetrics(setting,
UserHandle.getUid(userId, packageSetting.getAppId()),
- packageSetting.getEnabled(userId));
+ packageSetting.getEnabled(userId), callingUid);
if (!setEnabledSettingInternalLocked(computer, packageSetting, setting, userId,
callingPackage)) {
continue;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index b369f03d002f..23ae98325cb9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -19,7 +19,7 @@ package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
-import static android.content.pm.PackageManager.PROPERTY_ANDROID_SAFETY_LABEL_PATH;
+import static android.content.pm.PackageManager.PROPERTY_ANDROID_SAFETY_LABEL;
import static android.content.pm.SigningDetails.CertCapabilities.SHARED_USER_ID;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDWR;
@@ -71,8 +71,12 @@ import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.res.ApkAssets;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
import android.os.Binder;
import android.os.Build;
+import android.os.CancellationSignal;
import android.os.Debug;
import android.os.Environment;
import android.os.FileUtils;
@@ -93,6 +97,7 @@ import android.system.Os;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Base64;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.LogPrinter;
import android.util.Printer;
@@ -147,11 +152,10 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
/**
* Class containing helper methods for the PackageManagerService.
@@ -1668,11 +1672,11 @@ public class PackageManagerServiceUtils {
return true;
}
Map<String, Property> properties = pkg.getProperties();
- if (!properties.containsKey(PROPERTY_ANDROID_SAFETY_LABEL_PATH)) {
+ if (!properties.containsKey(PROPERTY_ANDROID_SAFETY_LABEL)) {
return false;
}
- Property fileInAPkPathProperty = properties.get(PROPERTY_ANDROID_SAFETY_LABEL_PATH);
- if (!fileInAPkPathProperty.isString()) {
+ Property fileInApkProperty = properties.get(PROPERTY_ANDROID_SAFETY_LABEL);
+ if (!fileInApkProperty.isResourceId()) {
return false;
}
if (isSystem && !appMetadataFile.getParentFile().exists()) {
@@ -1684,28 +1688,46 @@ public class PackageManagerServiceUtils {
return false;
}
}
- String fileInApkPath = fileInAPkPathProperty.getString();
List<AndroidPackageSplit> splits = pkg.getSplits();
+ AssetManager.Builder builder = new AssetManager.Builder();
for (int i = 0; i < splits.size(); i++) {
- try (ZipFile zipFile = new ZipFile(splits.get(i).getPath())) {
- ZipEntry zipEntry = zipFile.getEntry(fileInApkPath);
- if (zipEntry != null
- && (isSystem || zipEntry.getSize() <= getAppMetadataSizeLimit())) {
- try (InputStream in = zipFile.getInputStream(zipEntry)) {
- try (FileOutputStream out = new FileOutputStream(appMetadataFile)) {
- FileUtils.copy(in, out);
- Os.chmod(appMetadataFile.getAbsolutePath(),
- APP_METADATA_FILE_ACCESS_MODE);
- return true;
+ try {
+ builder.addApkAssets(ApkAssets.loadFromPath(splits.get(i).getPath()));
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to load resources from APK " + splits.get(i).getPath());
+ }
+ }
+ AssetManager assetManager = builder.build();
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ displayMetrics.setToDefaults();
+ Resources res = new Resources(assetManager, displayMetrics, null);
+ AtomicBoolean copyFailed = new AtomicBoolean(false);
+ try (InputStream in = res.openRawResource(fileInApkProperty.getResourceId())) {
+ try (FileOutputStream out = new FileOutputStream(appMetadataFile)) {
+ if (isSystem) {
+ FileUtils.copy(in, out);
+ } else {
+ long sizeLimit = getAppMetadataSizeLimit();
+ CancellationSignal signal = new CancellationSignal();
+ FileUtils.copy(in, out, signal, Runnable::run, (long progress) -> {
+ if (progress > sizeLimit) {
+ copyFailed.set(true);
+ signal.cancel();
}
- }
+ });
}
- } catch (Exception e) {
- Slog.e(TAG, e.getMessage());
+ Os.chmod(appMetadataFile.getAbsolutePath(),
+ APP_METADATA_FILE_ACCESS_MODE);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, e.getMessage());
+ copyFailed.set(true);
+ } finally {
+ if (copyFailed.get()) {
appMetadataFile.delete();
}
}
- return false;
+ return !copyFailed.get();
}
public static void linkFilesToOldDirs(@NonNull Installer installer,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 7a36f6dabe06..0a8b2b2c6219 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -328,6 +328,8 @@ class PackageManagerShellCommand extends ShellCommand {
return runGetPrivappDenyPermissions();
case "get-oem-permissions":
return runGetOemPermissions();
+ case "get-signature-permission-allowlist":
+ return runGetSignaturePermissionAllowlist();
case "trim-caches":
return runTrimCaches();
case "create-user":
@@ -2920,6 +2922,54 @@ class PackageManagerShellCommand extends ShellCommand {
return 0;
}
+ private int runGetSignaturePermissionAllowlist() {
+ final var partition = getNextArg();
+ if (partition == null) {
+ getErrPrintWriter().println("Error: no partition specified.");
+ return 1;
+ }
+ final var permissionAllowlist =
+ SystemConfig.getInstance().getPermissionAllowlist();
+ final ArrayMap<String, ArrayMap<String, Boolean>> allowlist;
+ switch (partition) {
+ case "system":
+ allowlist = permissionAllowlist.getSignatureAppAllowlist();
+ break;
+ case "vendor":
+ allowlist = permissionAllowlist.getVendorSignatureAppAllowlist();
+ break;
+ case "product":
+ allowlist = permissionAllowlist.getProductSignatureAppAllowlist();
+ break;
+ case "system-ext":
+ allowlist = permissionAllowlist.getSystemExtSignatureAppAllowlist();
+ break;
+ default:
+ getErrPrintWriter().println("Error: unknown partition: " + partition);
+ return 1;
+ }
+ final var ipw = new IndentingPrintWriter(getOutPrintWriter(), " ");
+ final var allowlistSize = allowlist.size();
+ for (var allowlistIndex = 0; allowlistIndex < allowlistSize; allowlistIndex++) {
+ final var packageName = allowlist.keyAt(allowlistIndex);
+ final var permissions = allowlist.valueAt(allowlistIndex);
+ ipw.print("Package: ");
+ ipw.println(packageName);
+ ipw.increaseIndent();
+ final var permissionsSize = permissions.size();
+ for (var permissionsIndex = 0; permissionsIndex < permissionsSize; permissionsIndex++) {
+ final var permissionName = permissions.keyAt(permissionsIndex);
+ final var granted = permissions.valueAt(permissionsIndex);
+ if (granted) {
+ ipw.print("Permission: ");
+ ipw.println(permissionName);
+ }
+ }
+ ipw.decreaseIndent();
+ }
+ return 0;
+ }
+
private int runTrimCaches() throws RemoteException {
String size = getNextArg();
if (size == null) {
@@ -4852,6 +4902,10 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" get-oem-permissions TARGET-PACKAGE");
pw.println(" Prints all OEM permissions for a package.");
pw.println("");
+ pw.println(" get-signature-permission-allowlist PARTITION");
+ pw.println(" Prints the signature permission allowlist for a partition.");
+ pw.println(" PARTITION is one of system, vendor, product and system-ext");
+ pw.println("");
pw.println(" trim-caches DESIRED_FREE_SPACE [internal|UUID]");
pw.println(" Trim cache files to reach the given free space.");
pw.println("");
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index 20598f91a51d..2081f73e7336 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -358,6 +358,7 @@ final class PackageMetrics {
public static class ComponentStateMetrics {
public int mUid;
+ public int mCallingUid;
public int mComponentOldState;
public int mComponentNewState;
public boolean mIsForWholeApp;
@@ -365,13 +366,14 @@ final class PackageMetrics {
@Nullable private String mClassName;
ComponentStateMetrics(@NonNull PackageManager.ComponentEnabledSetting setting, int uid,
- int componentOldState) {
+ int componentOldState, int callingUid) {
mUid = uid;
mComponentOldState = componentOldState;
mComponentNewState = setting.getEnabledState();
mIsForWholeApp = !setting.isComponent();
mPackageName = setting.getPackageName();
mClassName = setting.getClassName();
+ mCallingUid = callingUid;
}
public boolean isSameComponent(ActivityInfo activityInfo) {
@@ -412,14 +414,15 @@ final class PackageMetrics {
componentStateMetrics.mComponentOldState,
componentStateMetrics.mComponentNewState,
isLauncher,
- componentStateMetrics.mIsForWholeApp);
+ componentStateMetrics.mIsForWholeApp,
+ componentStateMetrics.mCallingUid);
}
}
private static void reportComponentStateChanged(int uid, int componentOldState,
- int componentNewState, boolean isLauncher, boolean isForWholeApp) {
+ int componentNewState, boolean isLauncher, boolean isForWholeApp, int callingUid) {
FrameworkStatsLog.write(FrameworkStatsLog.COMPONENT_STATE_CHANGED_REPORTED,
- uid, componentOldState, componentNewState, isLauncher, isForWholeApp);
+ uid, componentOldState, componentNewState, isLauncher, isForWholeApp, callingUid);
}
private static List<ResolveInfo> getHomeActivitiesResolveInfoAsUser(@NonNull Computer computer,
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 41d6288d4411..8d6d774a9959 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2142,7 +2142,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
ComponentName unflattenOriginalComponentName = ComponentName.unflattenFromString(
originalComponentName);
if (unflattenOriginalComponentName == null) {
- Slog.d(TAG, "Incorrect component name from the attributes");
+ Slog.wtf(TAG, "Incorrect component name: " + originalComponentName
+ + " from the attributes");
continue;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4ff345fbedf9..ebdca5bcec6f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1924,16 +1924,20 @@ public class UserManagerService extends IUserManager.Stub {
private void showConfirmCredentialToDisableQuietMode(
@UserIdInt int userId, @Nullable IntentSender target, @Nullable String callingPackage) {
if (android.app.admin.flags.Flags.quietModeCredentialBugFix()) {
- // TODO (b/308121702) It may be brittle to rely on user states to check profile state
- int state;
- synchronized (mUserStates) {
- state = mUserStates.get(userId, UserState.STATE_NONE);
- }
- if (state != UserState.STATE_NONE) {
- Slog.i(LOG_TAG,
- "showConfirmCredentialToDisableQuietMode() called too early, user " + userId
- + " is still alive.");
- return;
+ if (!android.multiuser.Flags.restrictQuietModeCredentialBugFixToManagedProfiles()
+ || getUserInfo(userId).isManagedProfile()) {
+ // TODO (b/308121702) It may be brittle to rely on user states to check managed
+ // profile state
+ int state;
+ synchronized (mUserStates) {
+ state = mUserStates.get(userId, UserState.STATE_NONE);
+ }
+ if (state != UserState.STATE_NONE) {
+ Slog.i(LOG_TAG,
+ "showConfirmCredentialToDisableQuietMode() called too early, managed "
+ + "user " + userId + " is still alive.");
+ return;
+ }
}
}
// otherwise, we show a profile challenge to trigger decryption of the user
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 49c4000d7308..9a4155122402 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -463,11 +463,17 @@ public class BatteryStatsImpl extends BatteryStats {
public static class BatteryStatsConfig {
static final int RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG = 1 << 0;
static final int RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG = 1 << 1;
- static final long DEFAULT_POWER_STATS_COLLECTION_THROTTLE_PERIOD =
- TimeUnit.HOURS.toMillis(1);
private final int mFlags;
- private SparseLongArray mPowerStatsThrottlePeriods;
+ private final Long mDefaultPowerStatsThrottlePeriod;
+ private final Map<String, Long> mPowerStatsThrottlePeriods;
+
+ @VisibleForTesting
+ public BatteryStatsConfig() {
+ mFlags = 0;
+ mDefaultPowerStatsThrottlePeriod = 0L;
+ mPowerStatsThrottlePeriods = Map.of();
+ }
private BatteryStatsConfig(Builder builder) {
int flags = 0;
@@ -478,6 +484,7 @@ public class BatteryStatsImpl extends BatteryStats {
flags |= RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
}
mFlags = flags;
+ mDefaultPowerStatsThrottlePeriod = builder.mDefaultPowerStatsThrottlePeriod;
mPowerStatsThrottlePeriods = builder.mPowerStatsThrottlePeriods;
}
@@ -485,7 +492,7 @@ public class BatteryStatsImpl extends BatteryStats {
* Returns whether a BatteryStats reset should occur on unplug when the battery level is
* high.
*/
- boolean shouldResetOnUnplugHighBatteryLevel() {
+ public boolean shouldResetOnUnplugHighBatteryLevel() {
return (mFlags & RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG)
== RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG;
}
@@ -494,14 +501,18 @@ public class BatteryStatsImpl extends BatteryStats {
* Returns whether a BatteryStats reset should occur on unplug if the battery charge a
* significant amount since it has been plugged in.
*/
- boolean shouldResetOnUnplugAfterSignificantCharge() {
+ public boolean shouldResetOnUnplugAfterSignificantCharge() {
return (mFlags & RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG)
== RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
}
- long getPowerStatsThrottlePeriod(@BatteryConsumer.PowerComponent int powerComponent) {
- return mPowerStatsThrottlePeriods.get(powerComponent,
- DEFAULT_POWER_STATS_COLLECTION_THROTTLE_PERIOD);
+ /**
+ * Returns the minimum amount of time (in millis) to wait between passes
+ * of power stats collection for the specified power component.
+ */
+ public long getPowerStatsThrottlePeriod(String powerComponentName) {
+ return mPowerStatsThrottlePeriods.getOrDefault(powerComponentName,
+ mDefaultPowerStatsThrottlePeriod);
}
/**
@@ -510,18 +521,19 @@ public class BatteryStatsImpl extends BatteryStats {
public static class Builder {
private boolean mResetOnUnplugHighBatteryLevel;
private boolean mResetOnUnplugAfterSignificantCharge;
- private SparseLongArray mPowerStatsThrottlePeriods;
+ public static final long DEFAULT_POWER_STATS_THROTTLE_PERIOD =
+ TimeUnit.HOURS.toMillis(1);
+ public static final long DEFAULT_POWER_STATS_THROTTLE_PERIOD_CPU =
+ TimeUnit.MINUTES.toMillis(1);
+ private long mDefaultPowerStatsThrottlePeriod = DEFAULT_POWER_STATS_THROTTLE_PERIOD;
+ private final Map<String, Long> mPowerStatsThrottlePeriods = new HashMap<>();
public Builder() {
mResetOnUnplugHighBatteryLevel = true;
mResetOnUnplugAfterSignificantCharge = true;
- mPowerStatsThrottlePeriods = new SparseLongArray();
- setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_CPU,
- TimeUnit.MINUTES.toMillis(1));
- setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
- TimeUnit.HOURS.toMillis(1));
- setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_WIFI,
- TimeUnit.HOURS.toMillis(1));
+ setPowerStatsThrottlePeriodMillis(BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_CPU),
+ DEFAULT_POWER_STATS_THROTTLE_PERIOD_CPU);
}
/**
@@ -553,9 +565,18 @@ public class BatteryStatsImpl extends BatteryStats {
* Sets the minimum amount of time (in millis) to wait between passes
* of power stats collection for the specified power component.
*/
- public Builder setPowerStatsThrottlePeriodMillis(
- @BatteryConsumer.PowerComponent int powerComponent, long periodMs) {
- mPowerStatsThrottlePeriods.put(powerComponent, periodMs);
+ public Builder setPowerStatsThrottlePeriodMillis(String powerComponentName,
+ long periodMs) {
+ mPowerStatsThrottlePeriods.put(powerComponentName, periodMs);
+ return this;
+ }
+
+ /**
+ * Sets the minimum amount of time (in millis) to wait between passes
+ * of power stats collection for any components not configured explicitly.
+ */
+ public Builder setDefaultPowerStatsThrottlePeriodMillis(long periodMs) {
+ mDefaultPowerStatsThrottlePeriod = periodMs;
return this;
}
}
@@ -1586,8 +1607,7 @@ public class BatteryStatsImpl extends BatteryStats {
protected final Constants mConstants;
@VisibleForTesting
- @GuardedBy("this")
- protected BatteryStatsConfig mBatteryStatsConfig;
+ protected final BatteryStatsConfig mBatteryStatsConfig;
@GuardedBy("this")
private AlarmManager mAlarmManager = null;
@@ -1933,6 +1953,11 @@ public class BatteryStatsImpl extends BatteryStats {
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return mBatteryStatsConfig.getPowerStatsThrottlePeriod(powerComponentName);
+ }
+
+ @Override
public PowerStatsUidResolver getUidResolver() {
return mPowerStatsUidResolver;
}
@@ -11167,19 +11192,14 @@ public class BatteryStatsImpl extends BatteryStats {
mConstants.MAX_HISTORY_FILES, mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator,
mClock, mMonotonicClock, traceDelegate, eventLogger);
- mCpuPowerStatsCollector = new CpuPowerStatsCollector(mPowerStatsCollectorInjector,
- mBatteryStatsConfig.getPowerStatsThrottlePeriod(
- BatteryConsumer.POWER_COMPONENT_CPU));
+ mCpuPowerStatsCollector = new CpuPowerStatsCollector(mPowerStatsCollectorInjector);
mCpuPowerStatsCollector.addConsumer(this::recordPowerStats);
mMobileRadioPowerStatsCollector = new MobileRadioPowerStatsCollector(
- mPowerStatsCollectorInjector, mBatteryStatsConfig.getPowerStatsThrottlePeriod(
- BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO));
+ mPowerStatsCollectorInjector);
mMobileRadioPowerStatsCollector.addConsumer(this::recordPowerStats);
- mWifiPowerStatsCollector = new WifiPowerStatsCollector(
- mPowerStatsCollectorInjector, mBatteryStatsConfig.getPowerStatsThrottlePeriod(
- BatteryConsumer.POWER_COMPONENT_WIFI));
+ mWifiPowerStatsCollector = new WifiPowerStatsCollector(mPowerStatsCollectorInjector);
mWifiPowerStatsCollector.addConsumer(this::recordPowerStats);
mStartCount++;
diff --git a/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
index f53a1b0682c0..b5ef67b44e75 100644
--- a/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
@@ -59,6 +59,7 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {
KernelCpuStatsReader getKernelCpuStatsReader();
ConsumedEnergyRetriever getConsumedEnergyRetriever();
IntSupplier getVoltageSupplier();
+ long getPowerStatsCollectionThrottlePeriod(String powerComponentName);
default int getDefaultCpuPowerBrackets() {
return DEFAULT_CPU_POWER_BRACKETS;
@@ -94,9 +95,11 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {
private int mLastVoltageMv;
private long[] mLastConsumedEnergyUws;
- public CpuPowerStatsCollector(Injector injector, long throttlePeriodMs) {
- super(injector.getHandler(), throttlePeriodMs, injector.getUidResolver(),
- injector.getClock());
+ CpuPowerStatsCollector(Injector injector) {
+ super(injector.getHandler(), injector.getPowerStatsCollectionThrottlePeriod(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_CPU)),
+ injector.getUidResolver(), injector.getClock());
mInjector = injector;
}
diff --git a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java
index 7bc681752802..a96e01bdeadf 100644
--- a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java
@@ -73,6 +73,7 @@ public class MobileRadioPowerStatsCollector extends PowerStatsCollector {
Handler getHandler();
Clock getClock();
PowerStatsUidResolver getUidResolver();
+ long getPowerStatsCollectionThrottlePeriod(String powerComponentName);
PackageManager getPackageManager();
ConsumedEnergyRetriever getConsumedEnergyRetriever();
IntSupplier getVoltageSupplier();
@@ -104,8 +105,11 @@ public class MobileRadioPowerStatsCollector extends PowerStatsCollector {
private long mLastCallDuration;
private long mLastScanDuration;
- public MobileRadioPowerStatsCollector(Injector injector, long throttlePeriodMs) {
- super(injector.getHandler(), throttlePeriodMs, injector.getUidResolver(),
+ MobileRadioPowerStatsCollector(Injector injector) {
+ super(injector.getHandler(), injector.getPowerStatsCollectionThrottlePeriod(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)),
+ injector.getUidResolver(),
injector.getClock());
mInjector = injector;
}
diff --git a/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java
index 632105352ad2..bd04199fc227 100644
--- a/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java
@@ -56,6 +56,7 @@ public class WifiPowerStatsCollector extends PowerStatsCollector {
Handler getHandler();
Clock getClock();
PowerStatsUidResolver getUidResolver();
+ long getPowerStatsCollectionThrottlePeriod(String powerComponentName);
PackageManager getPackageManager();
ConsumedEnergyRetriever getConsumedEnergyRetriever();
IntSupplier getVoltageSupplier();
@@ -92,9 +93,11 @@ public class WifiPowerStatsCollector extends PowerStatsCollector {
private final SparseArray<WifiScanTimes> mLastScanTimes = new SparseArray<>();
private long mLastWifiActiveDuration;
- public WifiPowerStatsCollector(Injector injector, long throttlePeriodMs) {
- super(injector.getHandler(), throttlePeriodMs, injector.getUidResolver(),
- injector.getClock());
+ WifiPowerStatsCollector(Injector injector) {
+ super(injector.getHandler(), injector.getPowerStatsCollectionThrottlePeriod(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_WIFI)),
+ injector.getUidResolver(), injector.getClock());
mInjector = injector;
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 3b9ad1915478..c1b825b3f8d1 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -836,9 +836,7 @@ public class StatsPullAtomService extends SystemService {
registerEventListeners();
});
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
- if (true) {
- initNetworkStatsManager();
- }
+ initNetworkStatsManager();
BackgroundThread.getHandler().post(() -> {
// Network stats related pullers can only be initialized after service is ready.
initAndRegisterNetworkStatsPullers();
@@ -859,9 +857,6 @@ public class StatsPullAtomService extends SystemService {
mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
mStatsSubscriptionsListener = new StatsSubscriptionsListener(mSubscriptionManager);
mStorageManager = (StorageManager) mContext.getSystemService(StorageManager.class);
- if (false) {
- initNetworkStatsManager();
- }
// Initialize DiskIO
mStoragedUidIoStatsReader = new StoragedUidIoStatsReader();
@@ -1043,10 +1038,8 @@ public class StatsPullAtomService extends SystemService {
*/
@NonNull
private NetworkStatsManager getNetworkStatsManager() {
- if (true) {
- if (mNetworkStatsManager == null) {
- throw new IllegalStateException("NetworkStatsManager is not ready");
- }
+ if (mNetworkStatsManager == null) {
+ throw new IllegalStateException("NetworkStatsManager is not ready");
}
return mNetworkStatsManager;
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index f6afc52fd8d8..3393d3e049e1 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -150,7 +150,11 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
@Override
public void onWindowInfosChanged(InputWindowHandle[] windowHandles,
DisplayInfo[] displayInfos) {
- mHandler.post(() -> onWindowInfosChangedInternal(windowHandles, displayInfos));
+ if (com.android.server.accessibility.Flags.removeOnWindowInfosChangedHandler()) {
+ onWindowInfosChangedInternal(windowHandles, displayInfos);
+ } else {
+ mHandler.post(() -> onWindowInfosChangedInternal(windowHandles, displayInfos));
+ }
}
private void onWindowInfosChangedInternal(InputWindowHandle[] windowHandles,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2b32a30c31b4..76e7f535c60f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -339,7 +339,6 @@ import android.service.contentcapture.ActivityEvent;
import android.service.dreams.DreamActivity;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArraySet;
-import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.MergedConfiguration;
@@ -2123,14 +2122,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (mWmService.mFlags.mInsetsDecoupledConfiguration) {
// When the stable configuration is the default behavior, override for the legacy apps
// without forward override flag.
- mResolveConfigHint.mUseOverrideInsetsForStableBounds =
+ mResolveConfigHint.mUseOverrideInsetsForConfig =
!info.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED)
&& !info.isChangeEnabled(
OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
} else {
// When the stable configuration is not the default behavior, forward overriding the
// listed apps.
- mResolveConfigHint.mUseOverrideInsetsForStableBounds =
+ mResolveConfigHint.mUseOverrideInsetsForConfig =
info.isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
}
@@ -5682,6 +5681,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else if (mTransitionController.inFinishingTransition(this)) {
mTransitionChangeFlags |= FLAGS_IS_OCCLUDED_NO_ANIMATION;
}
+ } else {
+ mTransitionChangeFlags &= ~FLAG_IS_OCCLUDED;
}
return;
}
@@ -6529,8 +6530,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// and the token could be null.
return;
}
- if (r.mDisplayContent.mDisplayRotationCompatPolicy != null) {
- r.mDisplayContent.mDisplayRotationCompatPolicy.onActivityRefreshed(r);
+ if (r.mDisplayContent.mActivityRefresher != null) {
+ r.mDisplayContent.mActivityRefresher.onActivityRefreshed(r);
}
}
@@ -8490,7 +8491,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mCompatDisplayInsets =
new CompatDisplayInsets(
mDisplayContent, this, letterboxedContainerBounds,
- mResolveConfigHint.mUseOverrideInsetsForStableBounds);
+ mResolveConfigHint.mUseOverrideInsetsForConfig);
}
private void clearSizeCompatModeAttributes() {
@@ -8570,8 +8571,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final int parentWindowingMode =
newParentConfiguration.windowConfiguration.getWindowingMode();
- applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig);
-
// Bubble activities should always fill their parent and should not be letterboxed.
final boolean isFixedOrientationLetterboxAllowed = !getLaunchedFromBubble()
&& (parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
@@ -8671,6 +8670,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
}
+ applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig);
+
logAppCompatState();
}
@@ -8689,14 +8690,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (mDisplayContent == null) {
return;
}
- final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
int rotation = newParentConfiguration.windowConfiguration.getRotation();
if (rotation == ROTATION_UNDEFINED && !isFixedRotationTransforming()) {
rotation = mDisplayContent.getRotation();
}
- if (!mResolveConfigHint.mUseOverrideInsetsForStableBounds
- || getCompatDisplayInsets() != null || isFloating(parentWindowingMode)
- || rotation == ROTATION_UNDEFINED) {
+ if (!mResolveConfigHint.mUseOverrideInsetsForConfig
+ || getCompatDisplayInsets() != null || shouldCreateCompatDisplayInsets()
+ || isFloating(parentWindowingMode) || rotation == ROTATION_UNDEFINED) {
// If the insets configuration decoupled logic is not enabled for the app, or the app
// already has a compat override, or the context doesn't contain enough info to
// calculate the override, skip the override.
@@ -8713,53 +8713,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Override starts here.
- final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
- final int dw = rotated ? mDisplayContent.mBaseDisplayHeight
- : mDisplayContent.mBaseDisplayWidth;
- final int dh = rotated ? mDisplayContent.mBaseDisplayWidth
- : mDisplayContent.mBaseDisplayHeight;
- final Rect nonDecorInsets = mDisplayContent.getDisplayPolicy()
- .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorInsets;
- // This should be the only place override the configuration for ActivityRecord. Override
- // the value if not calculated yet.
- Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- if (outAppBounds == null || outAppBounds.isEmpty()) {
- inOutConfig.windowConfiguration.setAppBounds(parentBounds);
- outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- outAppBounds.inset(nonDecorInsets);
- }
- float density = inOutConfig.densityDpi;
- if (density == Configuration.DENSITY_DPI_UNDEFINED) {
- density = newParentConfiguration.densityDpi;
- }
- density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
- if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- final int overrideScreenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
- inOutConfig.screenWidthDp = overrideScreenWidthDp;
- }
- if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- final int overrideScreenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
- inOutConfig.screenHeightDp = overrideScreenHeightDp;
- }
- if (inOutConfig.smallestScreenWidthDp
- == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
- && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
- // For the case of PIP transition and multi-window environment, the
- // smallestScreenWidthDp is handled already. Override only if the app is in
- // fullscreen.
- final DisplayInfo info = new DisplayInfo(mDisplayContent.getDisplayInfo());
- mDisplayContent.computeSizeRanges(info, rotated, dw, dh,
- mDisplayContent.getDisplayMetrics().density,
- inOutConfig, true /* overrideConfig */);
- }
-
- // It's possible that screen size will be considered in different orientation with or
- // without considering the system bar insets. Override orientation as well.
- if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
- inOutConfig.orientation =
- (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
- ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
- }
+ computeConfigByResolveHint(inOutConfig, newParentConfiguration);
}
private void computeConfigByResolveHint(@NonNull Configuration resolvedConfig,
@@ -9015,7 +8969,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (mDisplayContent == null) {
return true;
}
- if (!mResolveConfigHint.mUseOverrideInsetsForStableBounds) {
+ if (!mResolveConfigHint.mUseOverrideInsetsForConfig) {
// No insets should be considered any more.
return true;
}
@@ -9034,7 +8988,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final Task task = getTask();
task.calculateInsetFrames(outNonDecorBounds /* outNonDecorBounds */,
outStableBounds /* outStableBounds */, parentBounds /* bounds */, di,
- mResolveConfigHint.mUseOverrideInsetsForStableBounds);
+ mResolveConfigHint.mUseOverrideInsetsForConfig);
final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()
? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
// If orientation does not match the orientation with insets applied, then a
@@ -9091,7 +9045,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
getResolvedOverrideConfiguration().windowConfiguration.getBounds();
final int stableBoundsOrientation = stableBounds.width() > stableBounds.height()
? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
- final int parentOrientation = mResolveConfigHint.mUseOverrideInsetsForStableBounds
+ final int parentOrientation = mResolveConfigHint.mUseOverrideInsetsForConfig
? stableBoundsOrientation : newParentConfig.orientation;
// If the activity requires a different orientation (either by override or activityInfo),
@@ -9116,7 +9070,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
- final Rect parentAppBounds = mResolveConfigHint.mUseOverrideInsetsForStableBounds
+ final Rect parentAppBounds = mResolveConfigHint.mUseOverrideInsetsForConfig
? outNonDecorBounds : newParentConfig.windowConfiguration.getAppBounds();
// TODO(b/182268157): Explore using only one type of parentBoundsWithInsets, either app
// bounds or stable bounds to unify aspect ratio logic.
@@ -10042,7 +9996,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else {
scheduleConfigurationChanged(newMergedOverrideConfig, newActivityWindowInfo);
}
- notifyDisplayCompatPolicyAboutConfigurationChange(
+ notifyActivityRefresherAboutConfigurationChange(
mLastReportedConfiguration.getMergedConfiguration(), mTmpConfig);
return true;
}
@@ -10109,18 +10063,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else {
scheduleConfigurationChanged(newMergedOverrideConfig, newActivityWindowInfo);
}
- notifyDisplayCompatPolicyAboutConfigurationChange(
+ notifyActivityRefresherAboutConfigurationChange(
mLastReportedConfiguration.getMergedConfiguration(), mTmpConfig);
return true;
}
- private void notifyDisplayCompatPolicyAboutConfigurationChange(
+ private void notifyActivityRefresherAboutConfigurationChange(
Configuration newConfig, Configuration lastReportedConfig) {
- if (mDisplayContent.mDisplayRotationCompatPolicy == null
+ if (mDisplayContent.mActivityRefresher == null
|| !shouldBeResumed(/* activeActivity */ null)) {
return;
}
- mDisplayContent.mDisplayRotationCompatPolicy.onActivityConfigurationChanging(
+ mDisplayContent.mActivityRefresher.onActivityConfigurationChanging(
this, newConfig, lastReportedConfig);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRefresher.java b/services/core/java/com/android/server/wm/ActivityRefresher.java
new file mode 100644
index 000000000000..23a97089fd60
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ActivityRefresher.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.wm;
+
+import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+
+import android.annotation.NonNull;
+import android.app.servertransaction.RefreshCallbackItem;
+import android.app.servertransaction.ResumeActivityItem;
+import android.content.res.Configuration;
+import android.os.Handler;
+import android.os.RemoteException;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Class that refreshes the activity (through stop/pause -> resume) based on configuration change.
+ *
+ * <p>This class queries all of its {@link Evaluator}s and restarts the activity if any of them
+ * return {@code true} in {@link Evaluator#shouldRefreshActivity}. {@link ActivityRefresher} cycles
+ * through either stop or pause and then resume, based on the global config and per-app override.
+ */
+class ActivityRefresher {
+ // Delay for ensuring that onActivityRefreshed is always called after an activity refresh. The
+ // client process may not always report the event back to the server, such as process is
+ // crashed or got killed.
+ private static final long REFRESH_CALLBACK_TIMEOUT_MS = 2000L;
+
+ @NonNull private final WindowManagerService mWmService;
+ @NonNull private final Handler mHandler;
+ @NonNull private final ArrayList<Evaluator> mEvaluators = new ArrayList<>();
+
+ ActivityRefresher(@NonNull WindowManagerService wmService, @NonNull Handler handler) {
+ mWmService = wmService;
+ mHandler = handler;
+ }
+
+ void addEvaluator(@NonNull Evaluator evaluator) {
+ mEvaluators.add(evaluator);
+ }
+
+ void removeEvaluator(@NonNull Evaluator evaluator) {
+ mEvaluators.remove(evaluator);
+ }
+
+ /**
+ * "Refreshes" activity by going through "stopped -> resumed" or "paused -> resumed" cycle.
+ * This allows to clear cached values in apps (e.g. display or camera rotation) that influence
+ * camera preview and can lead to sideways or stretching issues persisting even after force
+ * rotation.
+ */
+ void onActivityConfigurationChanging(@NonNull ActivityRecord activity,
+ @NonNull Configuration newConfig, @NonNull Configuration lastReportedConfig) {
+ if (!shouldRefreshActivity(activity, newConfig, lastReportedConfig)) {
+ return;
+ }
+
+ final boolean cycleThroughStop =
+ mWmService.mLetterboxConfiguration
+ .isCameraCompatRefreshCycleThroughStopEnabled()
+ && !activity.mLetterboxUiController
+ .shouldRefreshActivityViaPauseForCameraCompat();
+
+ activity.mLetterboxUiController.setIsRefreshRequested(true);
+ ProtoLog.v(WM_DEBUG_STATES,
+ "Refreshing activity for freeform camera compatibility treatment, "
+ + "activityRecord=%s", activity);
+ final RefreshCallbackItem refreshCallbackItem = RefreshCallbackItem.obtain(
+ activity.token, cycleThroughStop ? ON_STOP : ON_PAUSE);
+ final ResumeActivityItem resumeActivityItem = ResumeActivityItem.obtain(
+ activity.token, /* isForward */ false, /* shouldSendCompatFakeFocus */ false);
+ try {
+ activity.mAtmService.getLifecycleManager().scheduleTransactionAndLifecycleItems(
+ activity.app.getThread(), refreshCallbackItem, resumeActivityItem);
+ mHandler.postDelayed(() -> {
+ synchronized (mWmService.mGlobalLock) {
+ onActivityRefreshed(activity);
+ }
+ }, REFRESH_CALLBACK_TIMEOUT_MS);
+ } catch (RemoteException e) {
+ activity.mLetterboxUiController.setIsRefreshRequested(false);
+ }
+ }
+
+ boolean isActivityRefreshing(@NonNull ActivityRecord activity) {
+ return activity.mLetterboxUiController.isRefreshRequested();
+ }
+
+ void onActivityRefreshed(@NonNull ActivityRecord activity) {
+ // TODO(b/333060789): can we tell that refresh did not happen by observing the activity
+ // state?
+ activity.mLetterboxUiController.setIsRefreshRequested(false);
+ }
+
+ private boolean shouldRefreshActivity(@NonNull ActivityRecord activity,
+ @NonNull Configuration newConfig, @NonNull Configuration lastReportedConfig) {
+ return mWmService.mLetterboxConfiguration.isCameraCompatRefreshEnabled()
+ && activity.mLetterboxUiController.shouldRefreshActivityForCameraCompat()
+ && ArrayUtils.find(mEvaluators.toArray(), evaluator ->
+ ((Evaluator) evaluator)
+ .shouldRefreshActivity(activity, newConfig, lastReportedConfig)) != null;
+ }
+
+ /**
+ * Interface for classes that would like to refresh the recently updated activity, based on the
+ * configuration change.
+ */
+ interface Evaluator {
+ boolean shouldRefreshActivity(@NonNull ActivityRecord activity,
+ @NonNull Configuration newConfig, @NonNull Configuration lastReportedConfig);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5079ec18bb0b..e49cb386ac49 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -478,6 +478,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final DisplayRotationCompatPolicy mDisplayRotationCompatPolicy;
@Nullable
final CameraStateMonitor mCameraStateMonitor;
+ @Nullable
+ final ActivityRefresher mActivityRefresher;
DisplayFrames mDisplayFrames;
final DisplayUpdater mDisplayUpdater;
@@ -1233,13 +1235,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mWmService.mLetterboxConfiguration.isCameraCompatTreatmentEnabledAtBuildTime();
if (shouldCreateDisplayRotationCompatPolicy) {
mCameraStateMonitor = new CameraStateMonitor(this, mWmService.mH);
+ mActivityRefresher = new ActivityRefresher(mWmService, mWmService.mH);
mDisplayRotationCompatPolicy = new DisplayRotationCompatPolicy(
- this, mWmService.mH, mCameraStateMonitor);
+ this, mCameraStateMonitor, mActivityRefresher);
mCameraStateMonitor.startListeningToCameraState();
} else {
// These are to satisfy the `final` check.
mCameraStateMonitor = null;
+ mActivityRefresher = null;
mDisplayRotationCompatPolicy = null;
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index eacf9a3fa759..e0cc064fcacc 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -18,8 +18,6 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
-import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
@@ -32,19 +30,14 @@ import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.view.Display.TYPE_INTERNAL;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_CAMERA_COMPAT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
-import android.app.servertransaction.RefreshCallbackItem;
-import android.app.servertransaction.ResumeActivityItem;
import android.content.pm.ActivityInfo.ScreenOrientation;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.os.Handler;
-import android.os.RemoteException;
import android.widget.Toast;
import com.android.internal.R;
@@ -64,48 +57,38 @@ import com.android.server.UiThread;
* R.bool.config_isWindowManagerCameraCompatTreatmentEnabled} is {@code true}.
*/
// TODO(b/261444714): Consider moving Camera-specific logic outside of the WM Core path
-class DisplayRotationCompatPolicy implements CameraStateMonitor.CameraCompatStateListener {
-
- // Delay for updating display rotation after Camera connection is closed. Needed to avoid
- // rotation flickering when an app is flipping between front and rear cameras or when size
- // compat mode is restarted.
- // TODO(b/263114289): Consider associating this delay with a specific activity so that if
- // the new non-camera activity started on top of the camer one we can rotate faster.
- private static final int CAMERA_CLOSED_ROTATION_UPDATE_DELAY_MS = 2000;
- // Delay for updating display rotation after Camera connection is opened. This delay is
- // selected to be long enough to avoid conflicts with transitions on the app's side.
- // Using a delay < CAMERA_CLOSED_ROTATION_UPDATE_DELAY_MS to avoid flickering when an app
- // is flipping between front and rear cameras (in case requested orientation changes at
- // runtime at the same time) or when size compat mode is restarted.
- private static final int CAMERA_OPENED_ROTATION_UPDATE_DELAY_MS =
- CAMERA_CLOSED_ROTATION_UPDATE_DELAY_MS / 2;
- // Delay for ensuring that onActivityRefreshed is always called after an activity refresh. The
- // client process may not always report the event back to the server, such as process is
- // crashed or got killed.
- private static final int REFRESH_CALLBACK_TIMEOUT_MS = 2000;
+final class DisplayRotationCompatPolicy implements CameraStateMonitor.CameraCompatStateListener,
+ ActivityRefresher.Evaluator {
+ @NonNull
private final DisplayContent mDisplayContent;
+ @NonNull
private final WindowManagerService mWmService;
+ @NonNull
private final CameraStateMonitor mCameraStateMonitor;
- private final Handler mHandler;
+ @NonNull
+ private final ActivityRefresher mActivityRefresher;
@ScreenOrientation
private int mLastReportedOrientation = SCREEN_ORIENTATION_UNSET;
- DisplayRotationCompatPolicy(@NonNull DisplayContent displayContent, Handler handler,
- @NonNull CameraStateMonitor cameraStateMonitor) {
+ DisplayRotationCompatPolicy(@NonNull DisplayContent displayContent,
+ @NonNull CameraStateMonitor cameraStateMonitor,
+ @NonNull ActivityRefresher activityRefresher) {
// This constructor is called from DisplayContent constructor. Don't use any fields in
// DisplayContent here since they aren't guaranteed to be set.
- mHandler = handler;
mDisplayContent = displayContent;
mWmService = displayContent.mWmService;
mCameraStateMonitor = cameraStateMonitor;
mCameraStateMonitor.addCameraStateListener(this);
+ mActivityRefresher = activityRefresher;
+ mActivityRefresher.addEvaluator(this);
}
/** Releases camera state listener. */
void dispose() {
mCameraStateMonitor.removeCameraStateListener(this);
+ mActivityRefresher.removeEvaluator(this);
}
/**
@@ -169,47 +152,6 @@ class DisplayRotationCompatPolicy implements CameraStateMonitor.CameraCompatStat
}
/**
- * "Refreshes" activity by going through "stopped -> resumed" or "paused -> resumed" cycle.
- * This allows to clear cached values in apps (e.g. display or camera rotation) that influence
- * camera preview and can lead to sideways or stretching issues persisting even after force
- * rotation.
- */
- void onActivityConfigurationChanging(ActivityRecord activity, Configuration newConfig,
- Configuration lastReportedConfig) {
- if (!isTreatmentEnabledForDisplay()
- || !mWmService.mLetterboxConfiguration.isCameraCompatRefreshEnabled()
- || !shouldRefreshActivity(activity, newConfig, lastReportedConfig)) {
- return;
- }
- boolean cycleThroughStop =
- mWmService.mLetterboxConfiguration
- .isCameraCompatRefreshCycleThroughStopEnabled()
- && !activity.mLetterboxUiController
- .shouldRefreshActivityViaPauseForCameraCompat();
- try {
- activity.mLetterboxUiController.setIsRefreshAfterRotationRequested(true);
- ProtoLog.v(WM_DEBUG_STATES,
- "Refreshing activity for camera compatibility treatment, "
- + "activityRecord=%s", activity);
- final RefreshCallbackItem refreshCallbackItem = RefreshCallbackItem.obtain(
- activity.token, cycleThroughStop ? ON_STOP : ON_PAUSE);
- final ResumeActivityItem resumeActivityItem = ResumeActivityItem.obtain(
- activity.token, /* isForward */ false, /* shouldSendCompatFakeFocus */ false);
- activity.mAtmService.getLifecycleManager().scheduleTransactionAndLifecycleItems(
- activity.app.getThread(), refreshCallbackItem, resumeActivityItem);
- mHandler.postDelayed(
- () -> onActivityRefreshed(activity),
- REFRESH_CALLBACK_TIMEOUT_MS);
- } catch (RemoteException e) {
- activity.mLetterboxUiController.setIsRefreshAfterRotationRequested(false);
- }
- }
-
- void onActivityRefreshed(@NonNull ActivityRecord activity) {
- activity.mLetterboxUiController.setIsRefreshAfterRotationRequested(false);
- }
-
- /**
* Notifies that animation in {@link ScreenRotationAnimation} has finished.
*
* <p>This class uses this signal as a trigger for notifying the user about forced rotation
@@ -276,14 +218,16 @@ class DisplayRotationCompatPolicy implements CameraStateMonitor.CameraCompatStat
// Refreshing only when configuration changes after rotation or camera split screen aspect ratio
// treatment is enabled
- private boolean shouldRefreshActivity(ActivityRecord activity, Configuration newConfig,
- Configuration lastReportedConfig) {
+ @Override
+ public boolean shouldRefreshActivity(@NonNull ActivityRecord activity,
+ @NonNull Configuration newConfig, @NonNull Configuration lastReportedConfig) {
final boolean displayRotationChanged = (newConfig.windowConfiguration.getDisplayRotation()
!= lastReportedConfig.windowConfiguration.getDisplayRotation());
- return (displayRotationChanged
- || activity.mLetterboxUiController.isCameraCompatSplitScreenAspectRatioAllowed())
+ return isTreatmentEnabledForDisplay()
&& isTreatmentEnabledForActivity(activity)
- && activity.mLetterboxUiController.shouldRefreshActivityForCameraCompat();
+ && activity.mLetterboxUiController.shouldRefreshActivityForCameraCompat()
+ && (displayRotationChanged
+ || activity.mLetterboxUiController.isCameraCompatSplitScreenAspectRatioAllowed());
}
/**
@@ -310,7 +254,6 @@ class DisplayRotationCompatPolicy implements CameraStateMonitor.CameraCompatStat
&& activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
}
-
/**
* Whether camera compat treatment is applicable for the given activity.
*
@@ -429,6 +372,6 @@ class DisplayRotationCompatPolicy implements CameraStateMonitor.CameraCompatStat
|| !mCameraStateMonitor.isCameraWithIdRunningForActivity(topActivity, cameraId)) {
return false;
}
- return topActivity.mLetterboxUiController.isRefreshAfterRotationRequested();
+ return mActivityRefresher.isActivityRefreshing(topActivity);
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 4400ed23a1b7..2288fe998b58 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -198,7 +198,7 @@ class InsetsSourceProvider {
if (mControllable) {
mWindowContainer.setControllableInsetProvider(this);
if (mPendingControlTarget != mControlTarget) {
- updateControlForTarget(mPendingControlTarget, true /* force */);
+ mStateController.notifyControlTargetChanged(mPendingControlTarget, this);
}
}
}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 57827c567b5b..16d7b4fb6eed 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -260,7 +260,7 @@ final class LetterboxUiController {
// Whether activity "refresh" was requested but not finished in
// ActivityRecord#activityResumedLocked following the camera compat force rotation in
// DisplayRotationCompatPolicy.
- private boolean mIsRefreshAfterRotationRequested;
+ private boolean mIsRefreshRequested;
@NonNull
private final OptProp mIgnoreRequestedOrientationOptProp;
@@ -571,15 +571,14 @@ final class LetterboxUiController {
}
/**
- * Whether activity "refresh" was requested but not finished in {@link #activityResumedLocked}
- * following the camera compat force rotation in {@link DisplayRotationCompatPolicy}.
+ * Whether activity "refresh" was requested but not finished in {@link #activityResumedLocked}.
*/
- boolean isRefreshAfterRotationRequested() {
- return mIsRefreshAfterRotationRequested;
+ boolean isRefreshRequested() {
+ return mIsRefreshRequested;
}
- void setIsRefreshAfterRotationRequested(boolean isRequested) {
- mIsRefreshAfterRotationRequested = isRequested;
+ void setIsRefreshRequested(boolean isRequested) {
+ mIsRefreshRequested = isRequested;
}
boolean isOverrideRespectRequestedOrientationEnabled() {
@@ -1068,7 +1067,7 @@ final class LetterboxUiController {
* thin letteboxing
*/
boolean allowVerticalReachabilityForThinLetterbox() {
- if (!Flags.disableThinLetterboxingReachability()) {
+ if (!Flags.disableThinLetterboxingPolicy()) {
return true;
}
// When the flag is enabled we allow vertical reachability only if the
@@ -1081,7 +1080,7 @@ final class LetterboxUiController {
* thin letteboxing
*/
boolean allowHorizontalReachabilityForThinLetterbox() {
- if (!Flags.disableThinLetterboxingReachability()) {
+ if (!Flags.disableThinLetterboxingPolicy()) {
return true;
}
// When the flag is enabled we allow horizontal reachability only if the
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index a444c96eea97..26e4eaaedfe2 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -40,6 +40,8 @@ import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.UserHandle.USER_NULL;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
@@ -2222,7 +2224,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
static class ConfigOverrideHint {
@Nullable DisplayInfo mTmpOverrideDisplayInfo;
@Nullable ActivityRecord.CompatDisplayInsets mTmpCompatInsets;
- boolean mUseOverrideInsetsForStableBounds;
+ boolean mUseOverrideInsetsForConfig;
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@@ -2255,11 +2257,11 @@ class TaskFragment extends WindowContainer<WindowContainer> {
@NonNull Configuration parentConfig, @Nullable ConfigOverrideHint overrideHint) {
DisplayInfo overrideDisplayInfo = null;
ActivityRecord.CompatDisplayInsets compatInsets = null;
- boolean useOverrideInsetsForStableBounds = false;
+ boolean useOverrideInsetsForConfig = false;
if (overrideHint != null) {
overrideDisplayInfo = overrideHint.mTmpOverrideDisplayInfo;
compatInsets = overrideHint.mTmpCompatInsets;
- useOverrideInsetsForStableBounds = overrideHint.mUseOverrideInsetsForStableBounds;
+ useOverrideInsetsForConfig = overrideHint.mUseOverrideInsetsForConfig;
if (overrideDisplayInfo != null) {
// Make sure the screen related configs can be computed by the provided
// display info.
@@ -2323,6 +2325,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
}
+ boolean insetsOverrideApplied = false;
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
|| inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) {
@@ -2339,7 +2342,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// The non decor inset are areas that could never be removed in Honeycomb. See
// {@link WindowManagerPolicy#getNonDecorInsetsLw}.
calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di,
- useOverrideInsetsForStableBounds);
+ useOverrideInsetsForConfig);
} else {
// Apply the given non-decor and stable insets to calculate the corresponding bounds
// for screen size of configuration.
@@ -2356,8 +2359,21 @@ class TaskFragment extends WindowContainer<WindowContainer> {
intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
compatInsets.mStableInsets[rotation]);
outAppBounds.set(mTmpNonDecorBounds);
+ } else if (useOverrideInsetsForConfig) {
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ final int dw = rotated ? mDisplayContent.mBaseDisplayHeight
+ : mDisplayContent.mBaseDisplayWidth;
+ final int dh = rotated ? mDisplayContent.mBaseDisplayWidth
+ : mDisplayContent.mBaseDisplayHeight;
+ final DisplayPolicy.DecorInsets.Info decorInsets = mDisplayContent
+ .getDisplayPolicy().getDecorInsetsInfo(rotation, dw, dh);
+ mTmpStableBounds.set(outAppBounds);
+ mTmpStableBounds.inset(decorInsets.mOverrideConfigInsets);
+ outAppBounds.inset(decorInsets.mOverrideNonDecorInsets);
+ mTmpNonDecorBounds.set(outAppBounds);
+ // Record the override apply to avoid duplicated check.
+ insetsOverrideApplied = true;
} else {
- // Set to app bounds because it excludes decor insets.
mTmpNonDecorBounds.set(outAppBounds);
mTmpStableBounds.set(outAppBounds);
}
@@ -2399,6 +2415,11 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// from the parent task would result in applications loaded wrong resource.
inOutConfig.smallestScreenWidthDp =
Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
+ } else if (insetsOverrideApplied) {
+ // The smallest width should also consider insets. If the insets are overridden,
+ // use the overridden value.
+ inOutConfig.smallestScreenWidthDp =
+ Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
}
// otherwise, it will just inherit
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 74ca9ad687ea..97f1e19e35b1 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -122,7 +122,6 @@ static struct {
jmethodID interceptMotionBeforeQueueingNonInteractive;
jmethodID interceptKeyBeforeDispatching;
jmethodID dispatchUnhandledKey;
- jmethodID onPointerDisplayIdChanged;
jmethodID onPointerDownOutsideFocus;
jmethodID getVirtualKeyQuietTimeMillis;
jmethodID getExcludedDeviceNames;
@@ -786,12 +785,6 @@ void NativeInputManager::notifyPointerDisplayIdChanged(ui::LogicalDisplayId poin
} // release lock
mInputManager->getReader().requestRefreshConfiguration(
InputReaderConfiguration::Change::DISPLAY_INFO);
-
- // Notify the system.
- JNIEnv* env = jniEnv();
- env->CallVoidMethod(mServiceObj, gServiceClassInfo.onPointerDisplayIdChanged, pointerDisplayId,
- position.x, position.y);
- checkAndClearExceptionFromCallback(env, "onPointerDisplayIdChanged");
}
void NativeInputManager::notifyStickyModifierStateChanged(uint32_t modifierState,
@@ -2933,9 +2926,6 @@ int register_android_server_InputManager(JNIEnv* env) {
"dispatchUnhandledKey",
"(Landroid/os/IBinder;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;");
- GET_METHOD_ID(gServiceClassInfo.onPointerDisplayIdChanged, clazz, "onPointerDisplayIdChanged",
- "(IFF)V");
-
GET_METHOD_ID(gServiceClassInfo.notifyStickyModifierStateChanged, clazz,
"notifyStickyModifierStateChanged", "(II)V");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index d114337f9c6c..d733762e90e5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -217,7 +217,7 @@ final class DevicePolicyEngine {
<V> void setLocalPolicy(
@NonNull PolicyDefinition<V> policyDefinition,
@NonNull EnforcingAdmin enforcingAdmin,
- @Nullable PolicyValue<V> value,
+ @NonNull PolicyValue<V> value,
int userId,
boolean skipEnforcePolicy) {
Objects.requireNonNull(policyDefinition);
@@ -313,6 +313,7 @@ final class DevicePolicyEngine {
}
updateDeviceAdminServiceOnPolicyAddLocked(enforcingAdmin);
write();
+ applyToInheritableProfiles(policyDefinition, enforcingAdmin, value, userId);
}
// TODO: add more documentation on broadcasts/callbacks to use to get current enforced values
@@ -400,7 +401,7 @@ final class DevicePolicyEngine {
* else remove the policy from child.
*/
private <V> void applyToInheritableProfiles(PolicyDefinition<V> policyDefinition,
- EnforcingAdmin enforcingAdmin, PolicyValue<V> value, int userId) {
+ EnforcingAdmin enforcingAdmin, @Nullable PolicyValue<V> value, int userId) {
if (policyDefinition.isInheritable()) {
Binder.withCleanCallingIdentity(() -> {
List<UserInfo> userInfos = mUserManager.getProfiles(userId);
@@ -1742,14 +1743,17 @@ final class DevicePolicyEngine {
}
}
- <V> void reapplyAllPoliciesLocked() {
+ <V> void reapplyAllPoliciesOnBootLocked() {
for (PolicyKey policy : mGlobalPolicies.keySet()) {
PolicyState<?> policyState = mGlobalPolicies.get(policy);
// Policy definition and value will always be of the same type
PolicyDefinition<V> policyDefinition =
(PolicyDefinition<V>) policyState.getPolicyDefinition();
- PolicyValue<V> policyValue = (PolicyValue<V>) policyState.getCurrentResolvedPolicy();
- enforcePolicy(policyDefinition, policyValue, UserHandle.USER_ALL);
+ if (!policyDefinition.shouldSkipEnforcementIfNotChanged()) {
+ PolicyValue<V> policyValue =
+ (PolicyValue<V>) policyState.getCurrentResolvedPolicy();
+ enforcePolicy(policyDefinition, policyValue, UserHandle.USER_ALL);
+ }
}
for (int i = 0; i < mLocalPolicies.size(); i++) {
int userId = mLocalPolicies.keyAt(i);
@@ -1758,10 +1762,11 @@ final class DevicePolicyEngine {
// Policy definition and value will always be of the same type
PolicyDefinition<V> policyDefinition =
(PolicyDefinition<V>) policyState.getPolicyDefinition();
- PolicyValue<V> policyValue =
- (PolicyValue<V>) policyState.getCurrentResolvedPolicy();
- enforcePolicy(policyDefinition, policyValue, userId);
-
+ if (!policyDefinition.shouldSkipEnforcementIfNotChanged()) {
+ PolicyValue<V> policyValue =
+ (PolicyValue<V>) policyState.getCurrentResolvedPolicy();
+ enforcePolicy(policyDefinition, policyValue, userId);
+ }
}
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2b93d2132a8f..85d2a0df4fdc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3351,7 +3351,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
break;
case SystemService.PHASE_SYSTEM_SERVICES_READY:
synchronized (getLockObject()) {
- mDevicePolicyEngine.reapplyAllPoliciesLocked();
+ mDevicePolicyEngine.reapplyAllPoliciesOnBootLocked();
}
break;
case SystemService.PHASE_ACTIVITY_MANAGER_READY:
@@ -11443,7 +11443,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
setBackwardsCompatibleAppRestrictions(
caller, packageName, restrictions, caller.getUserHandle());
- } else if (Flags.dmrhCanSetAppRestriction()) {
+ } else if (Flags.dmrhSetAppRestrictions()) {
final boolean isRoleHolder;
if (who != null) {
// DO or PO
@@ -11484,10 +11484,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
new BundlePolicyValue(restrictions),
affectedUserId);
}
- Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
- changeIntent.setPackage(packageName);
- changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcastAsUser(changeIntent, UserHandle.of(affectedUserId));
} else {
mInjector.binderWithCleanCallingIdentity(() -> {
mUserManager.setApplicationRestrictions(packageName, restrictions,
@@ -12845,7 +12841,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return Bundle.EMPTY;
}
return policies.get(enforcingAdmin).getValue();
- } else if (Flags.dmrhCanSetAppRestriction()) {
+ } else if (Flags.dmrhSetAppRestrictions()) {
final boolean isRoleHolder;
if (who != null) {
// Caller is DO or PO. They cannot call this on parent
@@ -15770,8 +15766,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
userId);
List<Bundle> restrictions = new ArrayList<>();
- for (EnforcingAdmin admin : policies.keySet()) {
- restrictions.add(policies.get(admin).getValue());
+ for (PolicyValue<Bundle> policyValue: policies.values()) {
+ Bundle value = policyValue.getValue();
+ // Probably not necessary since setApplicationRestrictions only sets non-empty
+ // Bundle, but just in case.
+ if (value != null && !value.isEmpty()) {
+ restrictions.add(value);
+ }
}
return mInjector.binderWithCleanCallingIdentity(() -> {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
index 1000bfa5f6c9..cbd28475bc26 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
@@ -52,7 +52,18 @@ class EnterpriseSpecificIdCalculator {
EnterpriseSpecificIdCalculator(Context context) {
TelephonyManager telephonyService = context.getSystemService(TelephonyManager.class);
Preconditions.checkState(telephonyService != null, "Unable to access telephony service");
- mImei = telephonyService.getImei(0);
+
+ String imei;
+ try {
+ imei = telephonyService.getImei(0);
+ } catch (UnsupportedOperationException doesNotSupportGms) {
+ // Instead of catching the exception, we could check for FEATURE_TELEPHONY_GSM.
+ // However that runs the risk of changing a device's existing ESID if on these devices
+ // telephonyService.getImei() actually returns non-null even when the device does not
+ // declare FEATURE_TELEPHONY_GSM.
+ imei = null;
+ }
+ mImei = imei;
String meid;
try {
meid = telephonyService.getMeid(0);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 8d980b5031e2..8bec3847d8ca 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -51,6 +51,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
final class PolicyDefinition<V> {
@@ -82,6 +83,10 @@ final class PolicyDefinition<V> {
// them.
private static final int POLICY_FLAG_USER_RESTRICTION_POLICY = 1 << 4;
+ // Only invoke the policy enforcer callback when the policy value changes, and do not invoke the
+ // callback in other cases such as device reboots.
+ private static final int POLICY_FLAG_SKIP_ENFORCEMENT_IF_UNCHANGED = 1 << 5;
+
private static final MostRestrictive<Boolean> FALSE_MORE_RESTRICTIVE = new MostRestrictive<>(
List.of(new BooleanPolicyValue(false), new BooleanPolicyValue(true)));
@@ -231,11 +236,11 @@ final class PolicyDefinition<V> {
// Don't need to take in a resolution mechanism since its never used, but might
// need some refactoring to not always assume a non-null mechanism.
new MostRecent<>(),
- POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_NON_COEXISTABLE_POLICY,
- // Application restrictions are now stored and retrieved from DPMS, so no
- // enforcing is required, however DPMS calls into UM to set restrictions for
- // backwards compatibility.
- (Bundle value, Context context, Integer userId, PolicyKey policyKey) -> true,
+ // Only invoke the enforcement callback during policy change and not other state
+ POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE
+ | POLICY_FLAG_NON_COEXISTABLE_POLICY
+ | POLICY_FLAG_SKIP_ENFORCEMENT_IF_UNCHANGED,
+ PolicyEnforcerCallbacks::setApplicationRestrictions,
new BundlePolicySerializer());
/**
@@ -581,6 +586,10 @@ final class PolicyDefinition<V> {
return (mPolicyFlags & POLICY_FLAG_USER_RESTRICTION_POLICY) != 0;
}
+ boolean shouldSkipEnforcementIfNotChanged() {
+ return (mPolicyFlags & POLICY_FLAG_SKIP_ENFORCEMENT_IF_UNCHANGED) != 0;
+ }
+
@Nullable
PolicyValue<V> resolvePolicy(LinkedHashMap<EnforcingAdmin, PolicyValue<V>> adminsPolicy) {
return mResolutionMechanism.resolve(adminsPolicy);
@@ -610,7 +619,7 @@ final class PolicyDefinition<V> {
* {@link Object#equals} implementation.
*/
private PolicyDefinition(
- PolicyKey key,
+ @NonNull PolicyKey key,
ResolutionMechanism<V> resolutionMechanism,
QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback,
PolicySerializer<V> policySerializer) {
@@ -622,11 +631,12 @@ final class PolicyDefinition<V> {
* {@link Object#equals} and {@link Object#hashCode()} implementation.
*/
private PolicyDefinition(
- PolicyKey policyKey,
+ @NonNull PolicyKey policyKey,
ResolutionMechanism<V> resolutionMechanism,
int policyFlags,
QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback,
PolicySerializer<V> policySerializer) {
+ Objects.requireNonNull(policyKey);
mPolicyKey = policyKey;
mResolutionMechanism = resolutionMechanism;
mPolicyFlags = policyFlags;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 09eef451c547..04d277e6e667 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -37,11 +37,13 @@ import android.app.admin.flags.Flags;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -172,6 +174,29 @@ final class PolicyEnforcerCallbacks {
return true;
}
+
+ /**
+ * Application restrictions are stored and retrieved from DPMS, so no enforcing (aka pushing
+ * it to UMS) is required. Only need to send broadcast to the target user here as we rely on
+ * the inheritable policy propagation logic in PolicyEngine to apply this policy to multiple
+ * profiles. The broadcast should only be sent when an application restriction is set, so we
+ * rely on the POLICY_FLAG_SKIP_ENFORCEMENT_IF_UNCHANGED flag so DPE only invokes this callback
+ * when the policy is set, and not during system boot or other situations.
+ */
+ static boolean setApplicationRestrictions(Bundle bundle, Context context, Integer userId,
+ PolicyKey policyKey) {
+ Binder.withCleanCallingIdentity(() -> {
+ PackagePolicyKey key = (PackagePolicyKey) policyKey;
+ String packageName = key.getPackageName();
+ Objects.requireNonNull(packageName);
+ Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+ changeIntent.setPackage(packageName);
+ changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ context.sendBroadcastAsUser(changeIntent, UserHandle.of(userId));
+ });
+ return true;
+ }
+
private static class BlockingCallback {
private final CountDownLatch mLatch = new CountDownLatch(1);
private final AtomicReference<Boolean> mValue = new AtomicReference<>();
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodInfoUtilsTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodInfoUtilsTest.java
new file mode 100644
index 000000000000..50804da5a293
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodInfoUtilsTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 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.inputmethod;
+
+import static com.android.server.inputmethod.TestUtils.TEST_IME_ID1;
+import static com.android.server.inputmethod.TestUtils.TEST_IME_ID2;
+import static com.android.server.inputmethod.TestUtils.createFakeInputMethodInfo;
+import static com.android.server.inputmethod.TestUtils.createFakeSubtypes;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.inputmethod.InputMethodInfo;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+public final class InputMethodInfoUtilsTest {
+
+ @Test
+ public void testMarshalSameObject() {
+ final var imi = createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(3));
+ final byte[] buf = InputMethodInfoUtils.marshal(imi);
+
+ assertArrayEquals("The same value must be returned when called multiple times",
+ buf, InputMethodInfoUtils.marshal(imi));
+ assertArrayEquals("The same value must be returned when called multiple times",
+ buf, InputMethodInfoUtils.marshal(imi));
+ }
+
+ @Test
+ public void testMarshalDifferentObjects() {
+ final var imi1 = createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(3));
+ final var imi2 = createFakeInputMethodInfo(TEST_IME_ID2, createFakeSubtypes(0));
+
+ assertFalse("Different inputs must yield different byte patterns", Arrays.equals(
+ InputMethodInfoUtils.marshal(imi1), InputMethodInfoUtils.marshal(imi2)));
+ }
+
+ @NonNull
+ private static <T> T readTypedObject(byte[] data, @NonNull Parcelable.Creator<T> creator) {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ parcel.unmarshall(data, 0, data.length);
+ parcel.setDataPosition(0);
+ return Objects.requireNonNull(parcel.readTypedObject(creator));
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
+
+ @Test
+ public void testUnmarshalSameObject() {
+ final var imi = createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(3));
+ final var cloned = readTypedObject(InputMethodInfoUtils.marshal(imi),
+ InputMethodInfo.CREATOR);
+ assertEquals(imi.getPackageName(), cloned.getPackageName());
+ assertEquals(imi.getSubtypeCount(), cloned.getSubtypeCount());
+ }
+}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index 28a99f2f8e87..3b25cb13e66c 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -127,6 +127,7 @@ public class InputMethodManagerServiceTestBase {
protected IInputMethodInvoker mMockInputMethodInvoker;
protected InputMethodManagerService mInputMethodManagerService;
protected ServiceThread mServiceThread;
+ protected ServiceThread mPackageMonitorThread;
protected boolean mIsLargeScreen;
private InputManagerGlobal.TestSession mInputManagerGlobalSession;
@@ -222,10 +223,17 @@ public class InputMethodManagerServiceTestBase {
mServiceThread =
new ServiceThread(
- "TestServiceThread",
- Process.THREAD_PRIORITY_FOREGROUND, /* allowIo */
- false);
- mInputMethodManagerService = new InputMethodManagerService(mContext, mServiceThread,
+ "immstest1",
+ Process.THREAD_PRIORITY_FOREGROUND,
+ true /* allowIo */);
+ mPackageMonitorThread =
+ new ServiceThread(
+ "immstest2",
+ Process.THREAD_PRIORITY_FOREGROUND,
+ true /* allowIo */);
+ mInputMethodManagerService = new InputMethodManagerService(mContext,
+ InputMethodManagerService.shouldEnableExperimentalConcurrentMultiUserMode(mContext),
+ mServiceThread, mPackageMonitorThread,
unusedUserId -> mMockInputMethodBindingController);
spyOn(mInputMethodManagerService);
@@ -259,6 +267,10 @@ public class InputMethodManagerServiceTestBase {
mInputMethodManagerService.mInputMethodDeviceConfigs.destroy();
}
+ if (mPackageMonitorThread != null) {
+ mPackageMonitorThread.quitSafely();
+ }
+
if (mServiceThread != null) {
mServiceThread.quitSafely();
}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMapTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMapTest.java
new file mode 100644
index 000000000000..be7042177a35
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMapTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 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.inputmethod;
+
+import static com.android.server.inputmethod.TestUtils.TEST_IME_ID1;
+import static com.android.server.inputmethod.TestUtils.TEST_IME_ID2;
+import static com.android.server.inputmethod.TestUtils.TEST_IME_ID3;
+import static com.android.server.inputmethod.TestUtils.createFakeInputMethodInfo;
+import static com.android.server.inputmethod.TestUtils.createFakeSubtypes;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.util.ArrayMap;
+import android.view.inputmethod.InputMethodInfo;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Test;
+
+public final class InputMethodMapTest {
+
+ @NonNull
+ private static InputMethodMap toMap(InputMethodInfo... list) {
+ final ArrayMap<String, InputMethodInfo> map = new ArrayMap<>();
+ for (var imi : list) {
+ map.put(imi.getId(), imi);
+ }
+ return InputMethodMap.of(map);
+ }
+
+ @Test
+ public void testAreSameSameObject() {
+ final var imi1 = createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(0));
+ final var imi2 = createFakeInputMethodInfo(TEST_IME_ID2, createFakeSubtypes(3));
+ final var map = toMap(imi1, imi2);
+ assertTrue("Must return true for the same instance",
+ InputMethodMap.areSame(map, map));
+ }
+
+ @Test
+ public void testAreSameEquivalentObject() {
+ final var imi1 = createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(0));
+ final var imi2 = createFakeInputMethodInfo(TEST_IME_ID2, createFakeSubtypes(3));
+ assertTrue("Must return true for the equivalent instances",
+ InputMethodMap.areSame(toMap(imi1, imi2), toMap(imi1, imi2)));
+
+ assertTrue("Must return true for the equivalent instances",
+ InputMethodMap.areSame(toMap(imi1, imi2), toMap(imi2, imi1)));
+ }
+
+ @Test
+ public void testAreSameDifferentKeys() {
+ final var imi1 = createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(0));
+ final var imi2 = createFakeInputMethodInfo(TEST_IME_ID2, createFakeSubtypes(3));
+ final var imi3 = createFakeInputMethodInfo(TEST_IME_ID3, createFakeSubtypes(3));
+ assertFalse("Must return false if keys are different",
+ InputMethodMap.areSame(toMap(imi1), toMap(imi1, imi2)));
+ assertFalse("Must return false if keys are different",
+ InputMethodMap.areSame(toMap(imi1, imi2), toMap(imi1)));
+ assertFalse("Must return false if keys are different",
+ InputMethodMap.areSame(toMap(imi1, imi2), toMap(imi1, imi3)));
+ }
+
+ @Test
+ public void testAreSameDifferentValues() {
+ final var imi1_without_subtypes =
+ createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(0));
+ final var imi1_with_subtypes =
+ createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(3));
+ final var imi2 = createFakeInputMethodInfo(TEST_IME_ID2, createFakeSubtypes(3));
+ assertFalse("Must return false if values are different",
+ InputMethodMap.areSame(toMap(imi1_without_subtypes), toMap(imi1_with_subtypes)));
+ assertFalse("Must return false if values are different",
+ InputMethodMap.areSame(
+ toMap(imi1_without_subtypes, imi2),
+ toMap(imi1_with_subtypes, imi2)));
+ }
+}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/TestUtils.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/TestUtils.java
new file mode 100644
index 000000000000..c51ff87fdae5
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/TestUtils.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2024 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.inputmethod;
+
+import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+public final class TestUtils {
+ /**
+ * {@link ComponentName} for fake {@link InputMethodInfo}.
+ */
+ @NonNull
+ public static final ComponentName TEST_IME_ID1 = Objects.requireNonNull(
+ ComponentName.unflattenFromString("com.android.test.testime1/.InputMethod"));
+
+ /**
+ * {@link ComponentName} for fake {@link InputMethodInfo}.
+ */
+ @NonNull
+ public static final ComponentName TEST_IME_ID2 = Objects.requireNonNull(
+ ComponentName.unflattenFromString("com.android.test.testime2/.InputMethod"));
+
+ /**
+ * {@link ComponentName} for fake {@link InputMethodInfo}.
+ */
+ @NonNull
+ public static final ComponentName TEST_IME_ID3 = Objects.requireNonNull(
+ ComponentName.unflattenFromString("com.android.test.testime3/.InputMethod"));
+
+ /**
+ * Creates a list of fake {@link InputMethodSubtype} for unit testing for the given number.
+ *
+ * @param count The number of fake {@link InputMethodSubtype} objects
+ * @return The list of fake {@link InputMethodSubtype} objects
+ */
+ @NonNull
+ public static ArrayList<InputMethodSubtype> createFakeSubtypes(int count) {
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(count);
+ for (int i = 0; i < count; ++i) {
+ subtypes.add(
+ new InputMethodSubtype.InputMethodSubtypeBuilder()
+ .setSubtypeId(i + 0x100)
+ .setLanguageTag("en-US")
+ .setSubtypeNameOverride("TestSubtype" + i)
+ .build());
+ }
+ return subtypes;
+ }
+
+ /**
+ * Creates a fake {@link InputMethodInfo} for unit testing.
+ *
+ * @param componentName {@link ComponentName} of the fake {@link InputMethodInfo}
+ * @param subtypes A list of (fake) {@link InputMethodSubtype}
+ * @return a fake {@link InputMethodInfo} object
+ */
+ @NonNull
+ public static InputMethodInfo createFakeInputMethodInfo(
+ @NonNull ComponentName componentName, @NonNull ArrayList<InputMethodSubtype> subtypes) {
+ final ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = componentName.getPackageName();
+ ai.enabled = true;
+
+ final ServiceInfo si = new ServiceInfo();
+ si.applicationInfo = ai;
+ si.enabled = true;
+ si.packageName = componentName.getPackageName();
+ si.name = componentName.getClassName();
+ si.exported = true;
+ si.nonLocalizedLabel = "Fake Label";
+
+ final ResolveInfo ri = new ResolveInfo();
+ ri.serviceInfo = si;
+
+ return new InputMethodInfo(ri, false /* isAuxIme */, null /* settingsActivity */,
+ subtypes, 0 /* isDefaultResId */, false /* forceDefault */);
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
index d29bf1abd7a3..3635e9a749e2 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
@@ -19,6 +19,7 @@ package com.android.server.power.stats;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.BatteryManager;
@@ -49,9 +50,9 @@ public class BatteryStatsResetTest {
private static final int BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL = 100;
private MockClock mMockClock;
+ private BatteryStatsImpl.BatteryStatsConfig mConfig;
private MockBatteryStatsImpl mBatteryStatsImpl;
-
/**
* Battery status. Must be one of the following:
* {@link BatteryManager#BATTERY_STATUS_UNKNOWN}
@@ -91,8 +92,9 @@ public class BatteryStatsResetTest {
@Before
public void setUp() throws IOException {
+ mConfig = mock(BatteryStatsImpl.BatteryStatsConfig.class);
mMockClock = new MockClock();
- mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock,
+ mBatteryStatsImpl = new MockBatteryStatsImpl(mConfig, mMockClock,
Files.createTempDirectory("BatteryStatsResetTest").toFile());
mBatteryStatsImpl.onSystemReady(mock(Context.class));
@@ -110,10 +112,7 @@ public class BatteryStatsResetTest {
@Test
public void testResetOnUnplug_highBatteryLevel() {
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(true)
- .build());
+ when(mConfig.shouldResetOnUnplugHighBatteryLevel()).thenReturn(true);
long expectedResetTimeUs = 0;
@@ -137,10 +136,7 @@ public class BatteryStatsResetTest {
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
// disable high battery level reset on unplug.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(false)
- .build());
+ when(mConfig.shouldResetOnUnplugHighBatteryLevel()).thenReturn(false);
dischargeToLevel(60);
@@ -153,10 +149,7 @@ public class BatteryStatsResetTest {
@Test
public void testResetOnUnplug_significantCharge() {
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugAfterSignificantCharge(true)
- .build());
+ when(mConfig.shouldResetOnUnplugAfterSignificantCharge()).thenReturn(true);
long expectedResetTimeUs = 0;
unplugBattery();
@@ -186,10 +179,7 @@ public class BatteryStatsResetTest {
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
// disable reset on unplug after significant charge.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugAfterSignificantCharge(false)
- .build());
+ when(mConfig.shouldResetOnUnplugAfterSignificantCharge()).thenReturn(false);
// Battery level dropped below 20%.
dischargeToLevel(15);
@@ -256,11 +246,9 @@ public class BatteryStatsResetTest {
@Test
public void testResetWhilePluggedIn_longPlugIn() {
// disable high battery level reset on unplug.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(false)
- .setResetOnUnplugAfterSignificantCharge(false)
- .build());
+ when(mConfig.shouldResetOnUnplugHighBatteryLevel()).thenReturn(false);
+ when(mConfig.shouldResetOnUnplugAfterSignificantCharge()).thenReturn(false);
+
long expectedResetTimeUs = 0;
plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
index 2d7cb2245c0a..6edfedee9e5b 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
@@ -98,10 +98,12 @@ public class BatteryUsageStatsRule implements TestRule {
mFreqsByPolicy.put(0, new int[]{300000, 1000000, 2000000});
mFreqsByPolicy.put(4, new int[]{300000, 1000000, 2500000, 3000000});
mBatteryStatsConfigBuilder = new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_CPU,
- 10000)
- .setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
- 10000);
+ .setPowerStatsThrottlePeriodMillis(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_CPU), 10000)
+ .setPowerStatsThrottlePeriodMillis(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO), 10000);
}
private void initBatteryStats() {
@@ -290,7 +292,8 @@ public class BatteryUsageStatsRule implements TestRule {
public BatteryUsageStatsRule setPowerStatsThrottlePeriodMillis(int powerComponent,
long throttleMs) {
- mBatteryStatsConfigBuilder.setPowerStatsThrottlePeriodMillis(powerComponent, throttleMs);
+ mBatteryStatsConfigBuilder.setPowerStatsThrottlePeriodMillis(
+ BatteryConsumer.powerComponentIdToString(powerComponent), throttleMs);
return this;
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
index b5bdafeb4696..d1105a4a9077 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
@@ -129,6 +129,11 @@ public class CpuPowerStatsCollectorTest {
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public int getDefaultCpuPowerBrackets() {
return mDefaultCpuPowerBrackets;
}
@@ -418,8 +423,8 @@ public class CpuPowerStatsCollectorTest {
private CpuPowerStatsCollector createCollector(int defaultCpuPowerBrackets,
int defaultCpuPowerBracketsPerEnergyConsumer) {
CpuPowerStatsCollector collector = new CpuPowerStatsCollector(
- new TestInjector(defaultCpuPowerBrackets, defaultCpuPowerBracketsPerEnergyConsumer),
- 0);
+ new TestInjector(defaultCpuPowerBrackets, defaultCpuPowerBracketsPerEnergyConsumer)
+ );
collector.addConsumer(stats -> mCollectedStats = stats);
collector.setEnabled(true);
return collector;
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java
index ca58db1bcad5..0275319a40e2 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java
@@ -123,6 +123,11 @@ public class MobileRadioPowerStatsCollectorTest {
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -348,7 +353,7 @@ public class MobileRadioPowerStatsCollectorTest {
}
private PowerStats collectPowerStats(boolean perNetworkTypeData) throws Throwable {
- MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0);
+ MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector);
collector.setEnabled(true);
when(mConsumedEnergyRetriever.getEnergyConsumerIds(
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java
index d80ffb4a66c8..29ef3b6551a6 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java
@@ -114,6 +114,11 @@ public class MobileRadioPowerStatsProcessorTest {
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -186,7 +191,7 @@ public class MobileRadioPowerStatsProcessorTest {
aggregatedStats.setUidState(APP_UID, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND, 0);
aggregatedStats.setUidState(APP_UID2, STATE_PROCESS_STATE, PROCESS_STATE_CACHED, 0);
- MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0);
+ MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Initial empty ModemActivityInfo.
@@ -425,7 +430,7 @@ public class MobileRadioPowerStatsProcessorTest {
aggregatedStats.setUidState(APP_UID, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND, 0);
aggregatedStats.setUidState(APP_UID2, STATE_PROCESS_STATE, PROCESS_STATE_CACHED, 0);
- MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0);
+ MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Initial empty ModemActivityInfo.
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
index 1d48975c086e..2c03f9d1a9aa 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
@@ -72,6 +72,11 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
this(DEFAULT_CONFIG, clock, historyDirectory, handler, new PowerStatsUidResolver());
}
+ MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, File historyDirectory) {
+ this(config, clock, historyDirectory, new Handler(Looper.getMainLooper()),
+ new PowerStatsUidResolver());
+ }
+
MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, File historyDirectory,
Handler handler, PowerStatsUidResolver powerStatsUidResolver) {
super(config, clock, new MonotonicClock(0, clock), historyDirectory, handler,
@@ -137,13 +142,6 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
return MOBILE_RADIO_POWER_STATE_UPDATE_FREQ_MS;
}
- public MockBatteryStatsImpl setBatteryStatsConfig(BatteryStatsConfig config) {
- synchronized (this) {
- mBatteryStatsConfig = config;
- }
- return this;
- }
-
public MockBatteryStatsImpl setNetworkStats(NetworkStats networkStats) {
mNetworkStats = networkStats;
return this;
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java
index dadcf3f3871e..69d655bc35c0 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java
@@ -98,6 +98,11 @@ public class PhoneCallPowerStatsProcessorTest {
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -175,7 +180,7 @@ public class PhoneCallPowerStatsProcessorTest {
aggregatedPowerStats.setDeviceState(STATE_POWER, POWER_STATE_OTHER, 0);
aggregatedPowerStats.setDeviceState(STATE_SCREEN, SCREEN_STATE_ON, 0);
- MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0);
+ MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Initial empty ModemActivityInfo.
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
index b4c012b3460f..a280cfe176a3 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
@@ -138,6 +138,11 @@ public class WifiPowerStatsCollectorTest {
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -317,7 +322,7 @@ public class WifiPowerStatsCollectorTest {
private PowerStats collectPowerStats(boolean hasPowerReporting) {
when(mWifiManager.isEnhancedPowerReportingSupported()).thenReturn(hasPowerReporting);
- WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector, 0);
+ WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector);
collector.setEnabled(true);
when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.WIFI))
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsProcessorTest.java
index 257a1a67f7b0..3ceaf357150e 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsProcessorTest.java
@@ -142,6 +142,11 @@ public class WifiPowerStatsProcessorTest {
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -195,7 +200,7 @@ public class WifiPowerStatsProcessorTest {
PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(processor);
- WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector, 0);
+ WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Initial empty WifiActivityEnergyInfo.
@@ -307,7 +312,7 @@ public class WifiPowerStatsProcessorTest {
PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(processor);
- WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector, 0);
+ WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Initial empty WifiActivityEnergyInfo.
@@ -420,7 +425,7 @@ public class WifiPowerStatsProcessorTest {
PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(processor);
- WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector, 0);
+ WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Establish a baseline
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index cb4fc753aa4d..ca15aa2a9d52 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -30,7 +30,9 @@ import static com.android.window.flags.Flags.FLAG_ALWAYS_DRAW_MAGNIFICATION_FULL
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -42,6 +44,7 @@ import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -102,6 +105,7 @@ import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutT
import com.android.internal.accessibility.util.AccessibilityUtils;
import com.android.internal.accessibility.util.ShortcutUtils;
import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.content.PackageMonitor;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService.AccessibilityDisplayListener;
import com.android.server.accessibility.magnification.FullScreenMagnificationController;
@@ -1620,6 +1624,67 @@ public class AccessibilityManagerServiceTest {
.containsExactlyElementsIn(Set.of(daltonizerTile));
}
+ @Test
+ @EnableFlags(Flags.FLAG_MANAGER_PACKAGE_MONITOR_LOGIC_FIX)
+ public void onHandleForceStop_dontDoIt_packageEnabled_returnsTrue() {
+ setupShortcutTargetServices();
+ AccessibilityUserState userState = mA11yms.getCurrentUserState();
+ userState.mEnabledServices.addAll(
+ userState.mInstalledServices.stream().map(
+ (AccessibilityServiceInfo::getComponentName)).toList());
+ String[] packages = userState.mEnabledServices.stream().map(
+ ComponentName::getPackageName).toList().toArray(new String[0]);
+
+ PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
+ when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+ mA11yms.setPackageMonitor(monitor);
+
+ assertTrue(mA11yms.getPackageMonitor().onHandleForceStop(
+ new Intent(),
+ packages,
+ UserHandle.USER_SYSTEM,
+ false
+ ));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MANAGER_PACKAGE_MONITOR_LOGIC_FIX)
+ public void onHandleForceStop_doIt_packageEnabled_returnsFalse() {
+ setupShortcutTargetServices();
+ AccessibilityUserState userState = mA11yms.getCurrentUserState();
+ userState.mEnabledServices.addAll(
+ userState.mInstalledServices.stream().map(
+ (AccessibilityServiceInfo::getComponentName)).toList());
+ String[] packages = userState.mEnabledServices.stream().map(
+ ComponentName::getPackageName).toList().toArray(new String[0]);
+
+ PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
+ when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+ mA11yms.setPackageMonitor(monitor);
+
+ assertFalse(mA11yms.getPackageMonitor().onHandleForceStop(
+ new Intent(),
+ packages,
+ UserHandle.USER_SYSTEM,
+ true
+ ));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MANAGER_PACKAGE_MONITOR_LOGIC_FIX)
+ public void onHandleForceStop_dontDoIt_packageNotEnabled_returnsFalse() {
+ PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
+ when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+ mA11yms.setPackageMonitor(monitor);
+
+ assertFalse(mA11yms.getPackageMonitor().onHandleForceStop(
+ new Intent(),
+ new String[]{ "FOO", "BAR"},
+ UserHandle.USER_SYSTEM,
+ false
+ ));
+ }
+
private static AccessibilityServiceInfo mockAccessibilityServiceInfo(
ComponentName componentName) {
return mockAccessibilityServiceInfo(
@@ -1630,7 +1695,7 @@ public class AccessibilityManagerServiceTest {
ComponentName componentName,
boolean isSystemApp, boolean isAlwaysOnService) {
AccessibilityServiceInfo accessibilityServiceInfo =
- Mockito.spy(new AccessibilityServiceInfo());
+ spy(new AccessibilityServiceInfo());
accessibilityServiceInfo.setComponentName(componentName);
ResolveInfo mockResolveInfo = Mockito.mock(ResolveInfo.class);
when(accessibilityServiceInfo.getResolveInfo()).thenReturn(mockResolveInfo);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index b5f0a527de7b..b50684bb7a25 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -26,6 +26,8 @@ import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE;
+import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
+import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON;
import static com.google.common.truth.Truth.assertThat;
@@ -1780,9 +1782,17 @@ public class HdmiCecLocalDeviceTvTest {
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
- mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // RequestActiveSourceAction will start.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ // Skip the LauncherX API timeout.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
@@ -1791,6 +1801,10 @@ public class HdmiCecLocalDeviceTvTest {
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
mTestLooper.dispatchAll();
+ // Assume there was a retry and the action did not finish earlier.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
}
@@ -1800,9 +1814,18 @@ public class HdmiCecLocalDeviceTvTest {
HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
- mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
+
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // RequestActiveSourceAction will start.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ // Skip the LauncherX API timeout.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
@@ -1827,8 +1850,18 @@ public class HdmiCecLocalDeviceTvTest {
HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
- mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // RequestActiveSourceAction will start.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ // Skip the LauncherX API timeout.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
@@ -1847,8 +1880,16 @@ public class HdmiCecLocalDeviceTvTest {
HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
- mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // RequestActiveSourceAction will start.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
HdmiDeviceInfo playbackDevice = HdmiDeviceInfo.cecDeviceBuilder()
.setLogicalAddress(ADDR_PLAYBACK_1)
.setPhysicalAddress(0x1000)
@@ -1862,6 +1903,10 @@ public class HdmiCecLocalDeviceTvTest {
mHdmiControlService.getHdmiCecNetwork().addCecDevice(playbackDevice);
mTestLooper.dispatchAll();
+ // Skip the LauncherX API timeout.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
+ mTestLooper.dispatchAll();
+
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
mNativeWrapper.clearResultMessages();
mHdmiCecLocalDeviceTv.deviceSelect(playbackDevice.getId(), null);
@@ -1874,6 +1919,41 @@ public class HdmiCecLocalDeviceTvTest {
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
}
+ @Test
+ public void onAddressAllocated_sendSourceChangingMessage_noRequestActiveSourceMessage() {
+ HdmiCecMessage requestActiveSource =
+ HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
+ HdmiCecMessage activeSourceFromTv =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+ HdmiCecMessage setStreamPathFromTv =
+ HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2000);
+
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // RequestActiveSourceAction will start.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ // Even if the device at the end of this path doesn't answer to this message, TV should not
+ // continue the RequestActiveSourceAction.
+ mHdmiControlService.sendCecCommand(setStreamPathFromTv);
+
+ // Skip the LauncherX API timeout.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestActiveSource);
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ // Assume there was a retry and the action did not finish earlier.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
+ }
@Test
public void newDeviceConnectedIfOnlyOneGiveOsdNameSent() {
@@ -1900,7 +1980,12 @@ public class HdmiCecLocalDeviceTvTest {
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_WAKE_UP_MESSAGE);
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // TV will send <Active Source> when it selects its internal source.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
mTestLooper.dispatchAll();
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
@@ -1930,6 +2015,8 @@ public class HdmiCecLocalDeviceTvTest {
public void handleStandby_fromActiveSource_standby() {
mPowerManager.setInteractive(true);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
mHdmiControlService.setActiveSource(ADDR_PLAYBACK_1, 0x1000,
"HdmiCecLocalDeviceTvTest");
mTestLooper.dispatchAll();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
index a3d57c3df51e..70a003814036 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
@@ -24,6 +24,8 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.media.AudioAttributes.USAGE_NOTIFICATION;
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
@@ -52,6 +54,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.Manifest.permission;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.KeyguardManager;
@@ -190,6 +193,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase {
getContext().addMockSystemService(Vibrator.class, mVibrator);
getContext().addMockSystemService(PackageManager.class, mPackageManager);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
+ when(mPackageManager.checkPermission(eq(permission.RECEIVE_EMERGENCY_BROADCAST),
+ anyString())).thenReturn(PERMISSION_DENIED);
when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
@@ -2363,6 +2368,72 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase {
}
@Test
+ public void testBeepVolume_politeNotif_Avalanche_exemptEmergency() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
+ mSetFlagsRule.enableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS);
+ mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS_ATTN_UPDATE);
+ TestableFlagResolver flagResolver = new TestableFlagResolver();
+ flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50);
+ flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
+ initAttentionHelper(flagResolver);
+
+ // Trigger avalanche trigger intent
+ final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ intent.putExtra("state", false);
+ mAvalancheBroadcastReceiver.onReceive(getContext(), intent);
+
+ NotificationRecord r = getBeepyNotification();
+
+ // Grant RECEIVE_EMERGENCY_BROADCAST to notification's package
+ when(mPackageManager.checkPermission(eq(permission.RECEIVE_EMERGENCY_BROADCAST),
+ eq(r.getSbn().getPackageName()))).thenReturn(PERMISSION_GRANTED);
+
+ // Should beep at 100% volume
+ mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+ verifyBeepVolume(1.0f);
+ assertNotEquals(-1, r.getLastAudiblyAlertedMs());
+ verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
+ }
+
+ @Test
+ public void testBeepVolume_politeNotif_exemptEmergency() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
+ mSetFlagsRule.disableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS);
+ mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS_ATTN_UPDATE);
+ TestableFlagResolver flagResolver = new TestableFlagResolver();
+ flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50);
+ flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
+ // NOTIFICATION_COOLDOWN_ALL setting is enabled
+ Settings.System.putInt(getContext().getContentResolver(),
+ Settings.System.NOTIFICATION_COOLDOWN_ALL, 1);
+ initAttentionHelper(flagResolver);
+
+ NotificationRecord r = getBeepyNotification();
+
+ // Grant RECEIVE_EMERGENCY_BROADCAST to notification's package
+ when(mPackageManager.checkPermission(eq(permission.RECEIVE_EMERGENCY_BROADCAST),
+ eq(r.getSbn().getPackageName()))).thenReturn(PERMISSION_GRANTED);
+
+ // set up internal state
+ mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+ Mockito.reset(mRingtonePlayer);
+
+ // update should beep at 100% volume
+ NotificationRecord r2 = getBeepyNotification();
+ mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS);
+ assertNotEquals(-1, r2.getLastAudiblyAlertedMs());
+ verifyBeepVolume(1.0f);
+
+ // 2nd update should beep at 100% volume
+ Mockito.reset(mRingtonePlayer);
+ mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS);
+ assertNotEquals(-1, r2.getLastAudiblyAlertedMs());
+ verifyBeepVolume(1.0f);
+
+ verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt());
+ }
+
+ @Test
public void testBeepVolume_politeNotif_applyPerApp() throws Exception {
mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
mSetFlagsRule.disableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java
new file mode 100644
index 000000000000..12ab3e1bdf19
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.wm;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.servertransaction.RefreshCallbackItem;
+import android.app.servertransaction.ResumeActivityItem;
+import android.content.ComponentName;
+import android.content.res.Configuration;
+import android.os.Handler;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link ActivityRefresher}.
+ *
+ * <p>Build/Install/Run:
+ * atest WmTests:ActivityRefresherTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class ActivityRefresherTests extends WindowTestsBase {
+ private Handler mMockHandler;
+ private LetterboxConfiguration mLetterboxConfiguration;
+
+ private ActivityRecord mActivity;
+ private ActivityRefresher mActivityRefresher;
+
+ private ActivityRefresher.Evaluator mEvaluatorFalse =
+ (activity, newConfig, lastReportedConfig) -> false;
+
+ private ActivityRefresher.Evaluator mEvaluatorTrue =
+ (activity, newConfig, lastReportedConfig) -> true;
+
+ private final Configuration mNewConfig = new Configuration();
+ private final Configuration mOldConfig = new Configuration();
+
+ @Before
+ public void setUp() throws Exception {
+ mLetterboxConfiguration = mDisplayContent.mWmService.mLetterboxConfiguration;
+ spyOn(mLetterboxConfiguration);
+ when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled())
+ .thenReturn(true);
+ when(mLetterboxConfiguration.isCameraCompatRefreshEnabled())
+ .thenReturn(true);
+ when(mLetterboxConfiguration.isCameraCompatRefreshCycleThroughStopEnabled())
+ .thenReturn(true);
+
+ mMockHandler = mock(Handler.class);
+ when(mMockHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(
+ invocation -> {
+ ((Runnable) invocation.getArgument(0)).run();
+ return null;
+ });
+
+ mActivityRefresher = new ActivityRefresher(mDisplayContent.mWmService, mMockHandler);
+ }
+
+ @Test
+ public void testShouldRefreshActivity_refreshDisabled() throws Exception {
+ when(mLetterboxConfiguration.isCameraCompatRefreshEnabled())
+ .thenReturn(false);
+ configureActivityAndDisplay();
+ mActivityRefresher.addEvaluator(mEvaluatorTrue);
+
+ mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
+
+ assertActivityRefreshRequested(/* refreshRequested= */ false);
+ }
+
+ @Test
+ public void testShouldRefreshActivity_refreshDisabledForActivity() throws Exception {
+ configureActivityAndDisplay();
+ when(mActivity.mLetterboxUiController.shouldRefreshActivityForCameraCompat())
+ .thenReturn(false);
+ mActivityRefresher.addEvaluator(mEvaluatorTrue);
+
+ mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
+
+ assertActivityRefreshRequested(/* refreshRequested= */ false);
+ }
+
+ @Test
+ public void testShouldRefreshActivity_noRefreshTriggerers() throws Exception {
+ configureActivityAndDisplay();
+
+ mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
+
+ assertActivityRefreshRequested(/* refreshRequested= */ false);
+ }
+
+ @Test
+ public void testShouldRefreshActivity_refreshTriggerersReturnFalse() throws Exception {
+ configureActivityAndDisplay();
+ mActivityRefresher.addEvaluator(mEvaluatorFalse);
+
+ mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
+
+ assertActivityRefreshRequested(/* refreshRequested= */ false);
+ }
+
+ @Test
+ public void testShouldRefreshActivity_anyRefreshTriggerersReturnTrue() throws Exception {
+ configureActivityAndDisplay();
+ mActivityRefresher.addEvaluator(mEvaluatorFalse);
+ mActivityRefresher.addEvaluator(mEvaluatorTrue);
+
+ mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
+
+ assertActivityRefreshRequested(/* refreshRequested= */ true);
+ }
+
+ @Test
+ public void testOnActivityConfigurationChanging_cycleThroughStopDisabled()
+ throws Exception {
+ mActivityRefresher.addEvaluator(mEvaluatorTrue);
+ when(mLetterboxConfiguration.isCameraCompatRefreshCycleThroughStopEnabled())
+ .thenReturn(false);
+ configureActivityAndDisplay();
+
+ mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
+
+ assertActivityRefreshRequested(/* refreshRequested */ true, /* cycleThroughStop */ false);
+ }
+
+ @Test
+ public void testOnActivityConfigurationChanging_cycleThroughPauseEnabledForApp()
+ throws Exception {
+ configureActivityAndDisplay();
+ mActivityRefresher.addEvaluator(mEvaluatorTrue);
+ doReturn(true).when(mActivity.mLetterboxUiController)
+ .shouldRefreshActivityViaPauseForCameraCompat();
+
+ mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
+
+ assertActivityRefreshRequested(/* refreshRequested */ true, /* cycleThroughStop */ false);
+ }
+
+ @Test
+ public void testOnActivityRefreshed_setIsRefreshRequestedToFalse() throws Exception {
+ configureActivityAndDisplay();
+ mActivityRefresher.addEvaluator(mEvaluatorTrue);
+ doReturn(true).when(mActivity.mLetterboxUiController)
+ .shouldRefreshActivityViaPauseForCameraCompat();
+
+ mActivityRefresher.onActivityRefreshed(mActivity);
+
+ assertActivityRefreshRequested(false);
+ }
+
+ private void assertActivityRefreshRequested(boolean refreshRequested) throws Exception {
+ assertActivityRefreshRequested(refreshRequested, /* cycleThroughStop*/ true);
+ }
+
+ private void assertActivityRefreshRequested(boolean refreshRequested,
+ boolean cycleThroughStop) throws Exception {
+ verify(mActivity.mLetterboxUiController, times(refreshRequested ? 1 : 0))
+ .setIsRefreshRequested(true);
+
+ final RefreshCallbackItem refreshCallbackItem = RefreshCallbackItem.obtain(mActivity.token,
+ cycleThroughStop ? ON_STOP : ON_PAUSE);
+ final ResumeActivityItem resumeActivityItem = ResumeActivityItem.obtain(mActivity.token,
+ /* isForward */ false, /* shouldSendCompatFakeFocus */ false);
+
+ verify(mActivity.mAtmService.getLifecycleManager(), times(refreshRequested ? 1 : 0))
+ .scheduleTransactionAndLifecycleItems(mActivity.app.getThread(),
+ refreshCallbackItem, resumeActivityItem);
+ }
+
+ private void configureActivityAndDisplay() {
+ mActivity = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true)
+ .setDisplay(mDisplayContent)
+ // Set the component to be that of the test class in order to enable compat changes
+ .setComponent(ComponentName.createRelative(mContext,
+ ActivityRefresherTests.class.getName()))
+ .setWindowingMode(WINDOWING_MODE_FREEFORM)
+ .build()
+ .getTopMostActivity();
+
+ spyOn(mActivity.mLetterboxUiController);
+ doReturn(true).when(
+ mActivity.mLetterboxUiController).shouldRefreshActivityForCameraCompat();
+
+ doReturn(true).when(mActivity).inFreeformWindowingMode();
+ }
+}
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 262ba8bb32f3..c76acd7e1d6b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
@@ -91,6 +91,7 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
private CameraManager mMockCameraManager;
private Handler mMockHandler;
private LetterboxConfiguration mLetterboxConfiguration;
+ private ActivityRefresher mActivityRefresher;
private DisplayRotationCompatPolicy mDisplayRotationCompatPolicy;
private CameraManager.AvailabilityCallback mCameraAvailabilityCallback;
@@ -132,8 +133,9 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
});
CameraStateMonitor cameraStateMonitor =
new CameraStateMonitor(mDisplayContent, mMockHandler);
- mDisplayRotationCompatPolicy =
- new DisplayRotationCompatPolicy(mDisplayContent, mMockHandler, cameraStateMonitor);
+ mActivityRefresher = new ActivityRefresher(mDisplayContent.mWmService, mMockHandler);
+ mDisplayRotationCompatPolicy = new DisplayRotationCompatPolicy(mDisplayContent,
+ cameraStateMonitor, mActivityRefresher);
// Do not show the real toast.
spyOn(mDisplayRotationCompatPolicy);
@@ -606,7 +608,7 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
private void assertActivityRefreshRequested(boolean refreshRequested,
boolean cycleThroughStop) throws Exception {
verify(mActivity.mLetterboxUiController, times(refreshRequested ? 1 : 0))
- .setIsRefreshAfterRotationRequested(true);
+ .setIsRefreshRequested(true);
final RefreshCallbackItem refreshCallbackItem = RefreshCallbackItem.obtain(mActivity.token,
cycleThroughStop ? ON_STOP : ON_PAUSE);
@@ -628,7 +630,7 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
private void callOnActivityConfigurationChanging(
ActivityRecord activity, boolean isDisplayRotationChanging) {
- mDisplayRotationCompatPolicy.onActivityConfigurationChanging(activity,
+ mActivityRefresher.onActivityConfigurationChanging(activity,
/* newConfig */ createConfigurationWithDisplayRotation(ROTATION_0),
/* newConfig */ createConfigurationWithDisplayRotation(
isDisplayRotationChanging ? ROTATION_90 : ROTATION_0));
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 0e1a1af9bc48..c69faede7580 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -353,6 +353,17 @@ public class InsetsStateControllerTest extends WindowTestsBase {
}
@Test
+ public void testControlTargetChangedWhileProviderHasNoWindow() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ final InsetsSourceProvider provider = getController().getOrCreateSourceProvider(
+ ID_STATUS_BAR, statusBars());
+ getController().onBarControlTargetChanged(app, null, null, null);
+ assertNull(getController().getControlsForDispatch(app));
+ provider.setWindowContainer(createWindow(null, TYPE_APPLICATION, "statusBar"), null, null);
+ assertNotNull(getController().getControlsForDispatch(app));
+ }
+
+ @Test
public void testTransientVisibilityOfFixedRotationState() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 1195c934a6f7..6b17de4c8640 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -1594,7 +1594,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
}
@Test
- @EnableFlags(Flags.FLAG_DISABLE_THIN_LETTERBOXING_REACHABILITY)
+ @EnableFlags(Flags.FLAG_DISABLE_THIN_LETTERBOXING_POLICY)
public void testAllowReachabilityForThinLetterboxWithFlagEnabled() {
spyOn(mController);
doReturn(true).when(mController).isVerticalThinLetterboxed();
@@ -1609,7 +1609,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
}
@Test
- @DisableFlags(Flags.FLAG_DISABLE_THIN_LETTERBOXING_REACHABILITY)
+ @DisableFlags(Flags.FLAG_DISABLE_THIN_LETTERBOXING_POLICY)
public void testAllowReachabilityForThinLetterboxWithFlagDisabled() {
spyOn(mController);
doReturn(true).when(mController).isVerticalThinLetterboxed();
diff --git a/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml b/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
index 6f8f008cf85b..955b43a32827 100644
--- a/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
+++ b/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
@@ -19,7 +19,7 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.android.server.wm.flicker">
- <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="35"/>
<!-- Read and write traces from external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@@ -46,6 +46,8 @@
<uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
<!-- Allow the test to connect to perfetto trace processor -->
<uses-permission android:name="android.permission.INTERNET"/>
+ <!-- Allow to query for the Launcher TestInfo on SDK 30+ -->
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- Allow the test to write directly to /sdcard/ and connect to trace processor -->
<application android:requestLegacyExternalStorage="true"
android:networkSecurityConfig="@xml/network_security_config"
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
index cf4edd50040b..67825d2df361 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
@@ -43,6 +43,7 @@ import org.junit.runners.Parameterized
*
* To run this test: `atest FlickerTestsOther:OpenTrampolineActivityTest`
*/
+@FlakyTest(bugId = 341209752)
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@@ -168,7 +169,6 @@ class OpenTrampolineActivityTest(flicker: LegacyFlickerTest) : ActivityEmbedding
}
}
- @FlakyTest(bugId = 290736037)
/** Main activity should go from fullscreen to being a split with secondary activity. */
@Test
fun mainActivityLayerGoesFromFullscreenToSplit() {
@@ -203,7 +203,6 @@ class OpenTrampolineActivityTest(flicker: LegacyFlickerTest) : ActivityEmbedding
}
}
- @FlakyTest(bugId = 288591571)
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
super.visibleLayersShownMoreThanOneConsecutiveEntry()
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index bc3696b3ed1c..eed9225d3da0 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -205,7 +205,8 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) :
it.visibleRegion(ComponentNameMatcher.PIP_CONTENT_OVERLAY)
val secondaryVisibleRegion =
it.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- overlayVisibleRegion.coversExactly(secondaryVisibleRegion.region)
+ // TODO(b/340992001): replace coverAtLeast with coverExactly
+ overlayVisibleRegion.coversAtLeast(secondaryVisibleRegion.region)
}
.then()
.isInvisible(ComponentNameMatcher.PIP_CONTENT_OVERLAY)
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
index fb9258304870..379b45cdf08e 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
@@ -60,14 +60,16 @@ class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBa
testApp.launchViaIntent(wmHelper)
testApp.launchSecondaryActivity(wmHelper)
secondaryApp.launchViaIntent(wmHelper)
- tapl.goHome()
- wmHelper
- .StateSyncBuilder()
- .withAppTransitionIdle()
- .withHomeActivityVisible()
- .waitForAndVerify()
startDisplayBounds =
wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found")
+
+ // Record the displayBounds before `goHome()` in case the launcher is fixed-portrait.
+ tapl.goHome()
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withHomeActivityVisible()
+ .waitForAndVerify()
}
transitions {
SplitScreenUtils.enterSplit(
@@ -138,10 +140,6 @@ class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBa
check { "ActivityEmbeddingSplitHeight" }
.that(leftAELayerRegion.region.bounds.height())
.isEqual(rightAELayerRegion.region.bounds.height())
- check { "SystemSplitHeight" }
- .that(rightAELayerRegion.region.bounds.height())
- .isEqual(secondaryAppLayerRegion.region.bounds.height())
- // TODO(b/292283182): Remove this special case handling.
check { "ActivityEmbeddingSplitWidth" }
.that(
abs(
@@ -150,14 +148,6 @@ class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBa
)
)
.isLower(2)
- check { "SystemSplitWidth" }
- .that(
- abs(
- secondaryAppLayerRegion.region.bounds.width() -
- 2 * rightAELayerRegion.region.bounds.width()
- )
- )
- .isLower(2)
}
}
@@ -170,15 +160,9 @@ class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBa
visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
val rightAEWindowRegion =
visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- // There's no window for the divider bar.
- val secondaryAppLayerRegion =
- visibleRegion(ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
check { "ActivityEmbeddingSplitHeight" }
.that(leftAEWindowRegion.region.bounds.height())
.isEqual(rightAEWindowRegion.region.bounds.height())
- check { "SystemSplitHeight" }
- .that(rightAEWindowRegion.region.bounds.height())
- .isEqual(secondaryAppLayerRegion.region.bounds.height())
check { "ActivityEmbeddingSplitWidth" }
.that(
abs(
@@ -187,14 +171,6 @@ class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBa
)
)
.isLower(2)
- check { "SystemSplitWidth" }
- .that(
- abs(
- secondaryAppLayerRegion.region.bounds.width() -
- 2 * rightAEWindowRegion.region.bounds.width()
- )
- )
- .isLower(2)
}
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
index 86c21906163f..917aec1e809d 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
@@ -14,66 +14,71 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout
+<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
android:background="@android:color/holo_orange_light">
- <Button
- android:id="@+id/launch_secondary_activity_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:onClick="launchSecondaryActivity"
- android:tag="LEFT_TO_RIGHT"
- android:text="Launch Secondary Activity" />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <Button
- android:id="@+id/launch_secondary_activity_rtl_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:onClick="launchSecondaryActivity"
- android:tag="RIGHT_TO_LEFT"
- android:text="Launch Secondary Activity in RTL" />
+ <Button
+ android:id="@+id/launch_secondary_activity_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:onClick="launchSecondaryActivity"
+ android:tag="LEFT_TO_RIGHT"
+ android:text="Launch Secondary Activity" />
- <Button
- android:id="@+id/launch_secondary_activity_horizontally_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:onClick="launchSecondaryActivity"
- android:tag="BOTTOM_TO_TOP"
- android:text="Launch Secondary Activity Horizontally" />
+ <Button
+ android:id="@+id/launch_secondary_activity_rtl_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:onClick="launchSecondaryActivity"
+ android:tag="RIGHT_TO_LEFT"
+ android:text="Launch Secondary Activity in RTL" />
- <Button
- android:id="@+id/launch_placeholder_split_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:onClick="launchPlaceholderSplit"
- android:tag="LEFT_TO_RIGHT"
- android:text="Launch Placeholder Split" />
+ <Button
+ android:id="@+id/launch_secondary_activity_horizontally_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:onClick="launchSecondaryActivity"
+ android:tag="BOTTOM_TO_TOP"
+ android:text="Launch Secondary Activity Horizontally" />
- <Button
- android:id="@+id/launch_always_expand_activity_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:onClick="launchAlwaysExpandActivity"
- android:text="Launch Always Expand Activity" />
+ <Button
+ android:id="@+id/launch_placeholder_split_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:onClick="launchPlaceholderSplit"
+ android:tag="LEFT_TO_RIGHT"
+ android:text="Launch Placeholder Split" />
- <Button
- android:id="@+id/launch_placeholder_split_rtl_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:onClick="launchPlaceholderSplit"
- android:tag="RIGHT_TO_LEFT"
- android:text="Launch Placeholder Split in RTL" />
+ <Button
+ android:id="@+id/launch_always_expand_activity_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:onClick="launchAlwaysExpandActivity"
+ android:text="Launch Always Expand Activity" />
- <Button
- android:id="@+id/launch_trampoline_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:onClick="launchTrampolineActivity"
- android:tag="LEFT_TO_RIGHT"
- android:text="Launch Trampoline Activity" />
+ <Button
+ android:id="@+id/launch_placeholder_split_rtl_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:onClick="launchPlaceholderSplit"
+ android:tag="RIGHT_TO_LEFT"
+ android:text="Launch Placeholder Split in RTL" />
-</LinearLayout>
+ <Button
+ android:id="@+id/launch_trampoline_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:onClick="launchTrampolineActivity"
+ android:tag="LEFT_TO_RIGHT"
+ android:text="Launch Trampoline Activity" />
+
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/Input/src/android/hardware/input/KeyboardLayoutPreviewTests.kt b/tests/Input/src/android/hardware/input/KeyboardLayoutPreviewTests.kt
index 3a2a3be0690d..ae32bdaf80d7 100644
--- a/tests/Input/src/android/hardware/input/KeyboardLayoutPreviewTests.kt
+++ b/tests/Input/src/android/hardware/input/KeyboardLayoutPreviewTests.kt
@@ -16,6 +16,8 @@
package android.hardware.input
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.content.ContextWrapper
import android.graphics.drawable.Drawable
import android.platform.test.annotations.Presubmit
@@ -54,16 +56,16 @@ class KeyboardLayoutPreviewTests {
}
@Test
+ @EnableFlags(Flags.FLAG_KEYBOARD_LAYOUT_PREVIEW_FLAG)
fun testKeyboardLayoutDrawable_hasCorrectDimensions() {
- setFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_LAYOUT_PREVIEW_FLAG)
val drawable = createDrawable()!!
assertEquals(WIDTH, drawable.intrinsicWidth)
assertEquals(HEIGHT, drawable.intrinsicHeight)
}
@Test
+ @DisableFlags(Flags.FLAG_KEYBOARD_LAYOUT_PREVIEW_FLAG)
fun testKeyboardLayoutDrawable_isNull_ifFlagOff() {
- setFlagsRule.disableFlags(Flags.FLAG_KEYBOARD_LAYOUT_PREVIEW_FLAG)
assertNull(createDrawable())
}
} \ No newline at end of file
diff --git a/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt b/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt
index e2b0c36ae694..bcd56ad0c669 100644
--- a/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt
+++ b/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt
@@ -21,6 +21,7 @@ import android.content.ContextWrapper
import android.os.Handler
import android.os.HandlerExecutor
import android.os.test.TestLooper
+import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.Presubmit
import android.platform.test.flag.junit.SetFlagsRule
import android.view.KeyEvent
@@ -50,6 +51,10 @@ import kotlin.test.fail
*/
@Presubmit
@RunWith(MockitoJUnitRunner::class)
+@EnableFlags(
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG,
+ com.android.input.flags.Flags.FLAG_ENABLE_INPUT_FILTER_RUST_IMPL,
+)
class StickyModifierStateListenerTest {
@get:Rule
@@ -67,10 +72,6 @@ class StickyModifierStateListenerTest {
@Before
fun setUp() {
- // Enable Sticky keys feature
- rule.enableFlags(com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG)
- rule.enableFlags(com.android.input.flags.Flags.FLAG_ENABLE_INPUT_FILTER_RUST_IMPL)
-
context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManagerMock)
inputManager = InputManager(context)
diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java b/tests/Internal/src/com/android/internal/protolog/ProtologDataSourceTest.java
index 001a09a0225a..be9fb1b309f6 100644
--- a/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/ProtologDataSourceTest.java
@@ -34,7 +34,7 @@ import perfetto.protos.DataSourceConfigOuterClass;
import perfetto.protos.ProtologCommon;
import perfetto.protos.ProtologConfig;
-public class PerfettoDataSourceTest {
+public class ProtologDataSourceTest {
@Before
public void before() {
assumeTrue(android.tracing.Flags.perfettoProtologTracing());
diff --git a/tests/UsbManagerTests/src/android/hardware/usb/DeviceFilterTest.java b/tests/UsbManagerTests/src/android/hardware/usb/DeviceFilterTest.java
new file mode 100644
index 000000000000..d6f3148e64f1
--- /dev/null
+++ b/tests/UsbManagerTests/src/android/hardware/usb/DeviceFilterTest.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.usb.flags.Flags;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.XmlUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserFactory;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.StringReader;
+
+/**
+ * Unit tests for {@link android.hardware.usb.DeviceFilter}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class DeviceFilterTest {
+
+ private static final int VID = 10;
+ private static final int PID = 11;
+ private static final int CLASS = 12;
+ private static final int SUBCLASS = 13;
+ private static final int PROTOCOL = 14;
+ private static final String MANUFACTURER = "Google";
+ private static final String PRODUCT = "Test";
+ private static final String SERIAL_NO = "4AL23";
+ private static final String INTERFACE_NAME = "MTP";
+
+ private MockitoSession mStaticMockSession;
+
+ @Before
+ public void setUp() throws Exception {
+ mStaticMockSession = ExtendedMockito.mockitoSession()
+ .mockStatic(Flags.class)
+ .strictness(Strictness.WARN)
+ .startMocking();
+
+ when(Flags.enableInterfaceNameDeviceFilter()).thenReturn(true);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mStaticMockSession.finishMocking();
+ }
+
+ @Test
+ public void testConstructorFromValues_interfaceNameIsInitialized() {
+ DeviceFilter deviceFilter = new DeviceFilter(
+ VID, PID, CLASS, SUBCLASS, PROTOCOL, MANUFACTURER,
+ PRODUCT, SERIAL_NO, INTERFACE_NAME
+ );
+
+ verifyDeviceFilterConfigurationExceptInterfaceName(deviceFilter);
+ assertThat(deviceFilter.mInterfaceName).isEqualTo(INTERFACE_NAME);
+ }
+
+ @Test
+ public void testConstructorFromUsbDevice_interfaceNameIsNull() {
+ UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+ when(usbDevice.getVendorId()).thenReturn(VID);
+ when(usbDevice.getProductId()).thenReturn(PID);
+ when(usbDevice.getDeviceClass()).thenReturn(CLASS);
+ when(usbDevice.getDeviceSubclass()).thenReturn(SUBCLASS);
+ when(usbDevice.getDeviceProtocol()).thenReturn(PROTOCOL);
+ when(usbDevice.getManufacturerName()).thenReturn(MANUFACTURER);
+ when(usbDevice.getProductName()).thenReturn(PRODUCT);
+ when(usbDevice.getSerialNumber()).thenReturn(SERIAL_NO);
+
+ DeviceFilter deviceFilter = new DeviceFilter(usbDevice);
+
+ verifyDeviceFilterConfigurationExceptInterfaceName(deviceFilter);
+ assertThat(deviceFilter.mInterfaceName).isEqualTo(null);
+ }
+
+ @Test
+ public void testConstructorFromDeviceFilter_interfaceNameIsInitialized() {
+ DeviceFilter originalDeviceFilter = new DeviceFilter(
+ VID, PID, CLASS, SUBCLASS, PROTOCOL, MANUFACTURER,
+ PRODUCT, SERIAL_NO, INTERFACE_NAME
+ );
+
+ DeviceFilter deviceFilter = new DeviceFilter(originalDeviceFilter);
+
+ verifyDeviceFilterConfigurationExceptInterfaceName(deviceFilter);
+ assertThat(deviceFilter.mInterfaceName).isEqualTo(INTERFACE_NAME);
+ }
+
+
+ @Test
+ public void testReadFromXml_interfaceNamePresent_propertyIsInitialized() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device interface-name=\"MTP\"/>");
+
+ assertThat(deviceFilter.mInterfaceName).isEqualTo("MTP");
+ }
+
+ @Test
+ public void testReadFromXml_interfaceNameAbsent_propertyIsNull() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device vendor-id=\"1\" />");
+
+ assertThat(deviceFilter.mInterfaceName).isEqualTo(null);
+ }
+
+ @Test
+ public void testWrite_withInterfaceName() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device interface-name=\"MTP\"/>");
+ XmlSerializer serializer = Mockito.mock(XmlSerializer.class);
+
+ deviceFilter.write(serializer);
+
+ verify(serializer).attribute(null, "interface-name", "MTP");
+ }
+
+ @Test
+ public void testWrite_withoutInterfaceName() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device vendor-id=\"1\" />");
+ XmlSerializer serializer = Mockito.mock(XmlSerializer.class);
+
+ deviceFilter.write(serializer);
+
+ verify(serializer, times(0)).attribute(eq(null), eq("interface-name"), any());
+ }
+
+ @Test
+ public void testToString() {
+ DeviceFilter deviceFilter = new DeviceFilter(
+ VID, PID, CLASS, SUBCLASS, PROTOCOL, MANUFACTURER,
+ PRODUCT, SERIAL_NO, INTERFACE_NAME
+ );
+
+ assertThat(deviceFilter.toString()).isEqualTo(
+ "DeviceFilter[mVendorId=10,mProductId=11,mClass=12,mSubclass=13,mProtocol=14,"
+ + "mManufacturerName=Google,mProductName=Test,mSerialNumber=4AL23,"
+ + "mInterfaceName=MTP]");
+ }
+
+ @Test
+ public void testMatch_interfaceNameMatches_returnTrue() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml(
+ "<usb-device class=\"255\" subclass=\"255\" protocol=\"0\" "
+ + "interface-name=\"MTP\"/>");
+ UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+ when(usbDevice.getInterfaceCount()).thenReturn(1);
+ when(usbDevice.getInterface(0)).thenReturn(new UsbInterface(
+ /* id= */ 0,
+ /* alternateSetting= */ 0,
+ /* name= */ "MTP",
+ /* class= */ 255,
+ /* subClass= */ 255,
+ /* protocol= */ 0));
+
+ assertTrue(deviceFilter.matches(usbDevice));
+ }
+
+ @Test
+ public void testMatch_interfaceNameMismatch_returnFalse() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml(
+ "<usb-device class=\"255\" subclass=\"255\" protocol=\"0\" "
+ + "interface-name=\"MTP\"/>");
+ UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+ when(usbDevice.getInterfaceCount()).thenReturn(1);
+ when(usbDevice.getInterface(0)).thenReturn(new UsbInterface(
+ /* id= */ 0,
+ /* alternateSetting= */ 0,
+ /* name= */ "UVC",
+ /* class= */ 255,
+ /* subClass= */ 255,
+ /* protocol= */ 0));
+
+ assertFalse(deviceFilter.matches(usbDevice));
+ }
+
+ @Test
+ public void testMatch_interfaceNameMismatchFlagDisabled_returnTrue() throws Exception {
+ when(Flags.enableInterfaceNameDeviceFilter()).thenReturn(false);
+ DeviceFilter deviceFilter = getDeviceFilterFromXml(
+ "<usb-device class=\"255\" subclass=\"255\" protocol=\"0\" "
+ + "interface-name=\"MTP\"/>");
+ UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+ when(usbDevice.getInterfaceCount()).thenReturn(1);
+ when(usbDevice.getInterface(0)).thenReturn(new UsbInterface(
+ /* id= */ 0,
+ /* alternateSetting= */ 0,
+ /* name= */ "UVC",
+ /* class= */ 255,
+ /* subClass= */ 255,
+ /* protocol= */ 0));
+
+ assertTrue(deviceFilter.matches(usbDevice));
+ }
+
+ private void verifyDeviceFilterConfigurationExceptInterfaceName(DeviceFilter deviceFilter) {
+ assertThat(deviceFilter.mVendorId).isEqualTo(VID);
+ assertThat(deviceFilter.mProductId).isEqualTo(PID);
+ assertThat(deviceFilter.mClass).isEqualTo(CLASS);
+ assertThat(deviceFilter.mSubclass).isEqualTo(SUBCLASS);
+ assertThat(deviceFilter.mProtocol).isEqualTo(PROTOCOL);
+ assertThat(deviceFilter.mManufacturerName).isEqualTo(MANUFACTURER);
+ assertThat(deviceFilter.mProductName).isEqualTo(PRODUCT);
+ assertThat(deviceFilter.mSerialNumber).isEqualTo(SERIAL_NO);
+ }
+
+ private DeviceFilter getDeviceFilterFromXml(String xml) throws Exception {
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ XmlPullParser parser = factory.newPullParser();
+ parser.setInput(new StringReader(xml));
+ XmlUtils.nextElement(parser);
+
+ return DeviceFilter.read(parser);
+ }
+
+}