summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt1
-rw-r--r--core/api/module-lib-current.txt2
-rw-r--r--core/api/test-current.txt6
-rw-r--r--core/java/android/app/TaskInfo.java10
-rw-r--r--core/java/android/content/Context.java6
-rw-r--r--core/java/android/content/pm/LauncherApps.java3
-rw-r--r--core/java/android/content/pm/multiuser.aconfig10
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java19
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java8
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl3
-rw-r--r--core/java/android/os/flags.aconfig8
-rw-r--r--core/java/android/os/vibrator/VibrationConfig.java13
-rw-r--r--core/java/android/os/vibrator/persistence/ParsedVibration.java2
-rw-r--r--core/java/android/os/vibrator/persistence/VibrationXmlParser.java3
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/view/PointerIcon.java36
-rw-r--r--core/java/android/view/View.java5
-rw-r--r--core/java/android/view/ViewTraversalTracingStrings.java2
-rw-r--r--core/java/android/webkit/WebViewUpdateManager.java2
-rw-r--r--core/java/android/window/TaskFragmentAnimationParams.java2
-rw-r--r--core/java/android/window/flags/large_screen_experiences_app_compat.aconfig8
-rw-r--r--core/java/android/window/flags/lse_desktop_experience.aconfig7
-rw-r--r--core/proto/android/providers/settings/system.proto1
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--core/res/res/drawable/pointer_alias_vector.xml4
-rw-r--r--core/res/res/drawable/pointer_all_scroll_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_arrow_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_cell_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_context_menu_vector.xml6
-rw-r--r--core/res/res/drawable/pointer_copy_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_crosshair_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_grab_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_grabbing_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_hand_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_handwriting_vector.xml4
-rw-r--r--core/res/res/drawable/pointer_help_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_horizontal_double_arrow_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_nodrop_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_text_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_top_left_diagonal_double_arrow_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_top_right_diagonal_double_arrow_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_vertical_double_arrow_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_vertical_text_vector.xml2
-rw-r--r--core/res/res/drawable/pointer_zoom_in_vector.xml4
-rw-r--r--core/res/res/drawable/pointer_zoom_out_vector.xml4
-rw-r--r--core/res/res/values/attrs.xml2
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/config_telephony.xml6
-rw-r--r--core/res/res/values/locale_config.xml38
-rw-r--r--core/res/res/values/styles.xml18
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java23
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java9
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp34
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/AndroidManifestRobolectric.xml1
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.pngbin0 -> 56309 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.pngbin0 -> 56309 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/robolectric/config/robolectric.properties1
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt94
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java46
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java17
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt43
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt64
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt137
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt30
-rw-r--r--packages/SettingsLib/ActionButtonsPreference/Android.bp1
-rw-r--r--packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java8
-rw-r--r--packages/SettingsLib/ActivityEmbedding/Android.bp1
-rw-r--r--packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java8
-rw-r--r--packages/SettingsLib/BannerMessagePreference/Android.bp1
-rw-r--r--packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java3
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp1
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java6
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarAppCompatActivity.java7
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java6
-rw-r--r--packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java4
-rw-r--r--packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java60
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java44
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/ZenModeRepository.kt8
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java78
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java5
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SystemUI/Android.bp5
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig19
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt24
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt63
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt94
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt6
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt5
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt74
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt18
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt1
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java19
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractorTest.kt41
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinatorTest.kt104
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java11
-rw-r--r--packages/SystemUI/res/drawable/hub_handle.xml20
-rw-r--r--packages/SystemUI/res/layout/app_clips_screenshot.xml4
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_container.xml13
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt8
-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/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt127
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt145
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt117
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt192
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt133
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationClassificationFlag.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinator.kt95
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt108
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt359
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt129
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt235
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt312
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt169
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt291
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java10
-rw-r--r--packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt19
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt5
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java8
-rw-r--r--services/core/java/com/android/server/OWNERS3
-rw-r--r--services/core/java/com/android/server/RescueParty.java21
-rw-r--r--services/core/java/com/android/server/am/LmkdConnection.java63
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java11
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java23
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java13
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java1
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java6
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java4
-rw-r--r--services/core/java/com/android/server/input/InputSettingsObserver.java14
-rw-r--r--services/core/java/com/android/server/input/PointerIconCache.java25
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java174
-rw-r--r--services/core/java/com/android/server/inputmethod/UserDataRepository.java7
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java7
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java3
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java8
-rw-r--r--services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java14
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationSettings.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java14
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java10
-rw-r--r--services/core/java/com/android/server/wm/DeviceStateController.java100
-rw-r--r--services/core/java/com/android/server/wm/Task.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java8
-rw-r--r--services/core/jni/Android.bp2
-rw-r--r--services/core/jni/com_android_server_vibrator_VibratorController.cpp81
-rw-r--r--services/java/com/android/server/SystemServer.java20
-rw-r--r--services/java/com/android/server/flags.aconfig7
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/PermissionService.kt2
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java9
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java2
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java30
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java143
-rw-r--r--tests/Input/assets/testPointerStrokeStyle.pngbin0 -> 378 bytes
-rw-r--r--tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt29
-rw-r--r--tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java55
227 files changed, 4067 insertions, 1842 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 8e4de7a15dd6..46f426b9f8e9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -12494,6 +12494,7 @@ package android.content.pm {
method @FlaggedApi("android.os.allow_private_profile") @Nullable @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public final android.content.pm.LauncherUserInfo getLauncherUserInfo(@NonNull android.os.UserHandle);
method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
method @FlaggedApi("android.os.allow_private_profile") @NonNull @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public java.util.List<java.lang.String> getPreInstalledSystemPackages(@NonNull android.os.UserHandle);
+ method @FlaggedApi("android.os.get_private_space_settings") @Nullable @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public android.content.IntentSender getPrivateSpaceSettingsIntent();
method @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public java.util.List<android.os.UserHandle> getProfiles();
method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
method @Nullable public android.content.IntentSender getShortcutConfigActivityIntent(@NonNull android.content.pm.LauncherActivityInfo);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index e4a840745ab3..7ae5d1be9773 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -674,7 +674,7 @@ package android.webkit {
method @Nullable public String getCurrentWebViewPackageName();
method @FlaggedApi("android.webkit.update_service_v2") @NonNull public android.webkit.WebViewProviderInfo getDefaultWebViewPackage();
method @Nullable public static android.webkit.WebViewUpdateManager getInstance();
- method @NonNull public android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
+ method @NonNull @RequiresPermission(allOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.QUERY_ALL_PACKAGES}) public android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
method @NonNull public android.webkit.WebViewProviderResponse waitForAndGetProvider();
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index b7de93aaaee3..099dbbc2764f 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2775,12 +2775,6 @@ package android.os.vibrator.persistence {
@FlaggedApi("android.os.vibrator.vibration_xml_apis") public final class ParsedVibration {
ctor public ParsedVibration(@NonNull java.util.List<android.os.VibrationEffect>);
- method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @Nullable public android.os.VibrationEffect resolve(@NonNull android.os.Vibrator);
- }
-
- @FlaggedApi("android.os.vibrator.vibration_xml_apis") public final class VibrationXmlParser {
- method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @NonNull public static android.os.vibrator.persistence.ParsedVibration parse(@NonNull java.io.InputStream) throws java.io.IOException;
- method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @NonNull public static android.os.VibrationEffect parseVibrationEffect(@NonNull java.io.InputStream) throws java.io.IOException;
}
public static final class VibrationXmlParser.ParseFailedException extends java.io.IOException {
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index ef8501f563dc..aca9bb4d07c1 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -297,6 +297,12 @@ public class TaskInfo {
public boolean isTopActivityTransparent;
/**
+ * Whether the top activity has specified style floating.
+ * @hide
+ */
+ public boolean isTopActivityStyleFloating;
+
+ /**
* Encapsulate specific App Compat information.
* @hide
*/
@@ -429,6 +435,7 @@ public class TaskInfo {
&& parentTaskId == that.parentTaskId
&& Objects.equals(topActivity, that.topActivity)
&& isTopActivityTransparent == that.isTopActivityTransparent
+ && isTopActivityStyleFloating == that.isTopActivityStyleFloating
&& appCompatTaskInfo.equalsForTaskOrganizer(that.appCompatTaskInfo);
}
@@ -498,6 +505,7 @@ public class TaskInfo {
mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR);
displayAreaFeatureId = source.readInt();
isTopActivityTransparent = source.readBoolean();
+ isTopActivityStyleFloating = source.readBoolean();
appCompatTaskInfo = source.readTypedObject(AppCompatTaskInfo.CREATOR);
}
@@ -545,6 +553,7 @@ public class TaskInfo {
dest.writeTypedObject(mTopActivityLocusId, flags);
dest.writeInt(displayAreaFeatureId);
dest.writeBoolean(isTopActivityTransparent);
+ dest.writeBoolean(isTopActivityStyleFloating);
dest.writeTypedObject(appCompatTaskInfo, flags);
}
@@ -582,6 +591,7 @@ public class TaskInfo {
+ " locusId=" + mTopActivityLocusId
+ " displayAreaFeatureId=" + displayAreaFeatureId
+ " isTopActivityTransparent=" + isTopActivityTransparent
+ + " isTopActivityStyleFloating=" + isTopActivityStyleFloating
+ " appCompatTaskInfo=" + appCompatTaskInfo
+ "}";
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ab58f43bf165..8365840b1efb 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2925,10 +2925,12 @@ public abstract class Context {
*/
@SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
- public abstract void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent,
+ public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent,
UserHandle user, String[] receiverPermissions, int appOp, Bundle options,
BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
- String initialData, Bundle initialExtras);
+ String initialData, Bundle initialExtras) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
/**
* Version of
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index df27f9d4e457..52c84dc0ac5d 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -935,12 +935,11 @@ public class LauncherApps {
*
* @return {@link IntentSender} object which launches the Private Space Settings Activity, if
* successful, null otherwise.
- * @hide
*/
// Alternatively, a system app can access this api for private profile if they've been granted
// with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
@Nullable
- @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
+ @FlaggedApi(Flags.FLAG_GET_PRIVATE_SPACE_SETTINGS)
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public IntentSender getPrivateSpaceSettingsIntent() {
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 124d07f7bb08..c7d94c66c81e 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -151,6 +151,16 @@ flag {
}
flag {
+ name: "fix_get_user_property_cache"
+ namespace: "multiuser"
+ description: "Cache is not optimised for getUserProperty for values below 0, eg. UserHandler.USER_NULL or UserHandle.USER_ALL"
+ bug: "350416200"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "cache_quiet_mode_state"
namespace: "multiuser"
description: "Optimise quiet mode state retrieval"
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 2ded615580fd..903e91646332 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -699,6 +699,25 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
/**
+ * Set whether the HAL should ignore display touches.
+ * Only applies to sensors where the HAL is reponsible for handling touches.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouch) {
+ if (mService == null) {
+ Slog.w(TAG, "setIgnoreDisplayTouches: no fingerprint service");
+ return;
+ }
+
+ try {
+ mService.setIgnoreDisplayTouches(requestId, sensorId, ignoreTouch);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Request fingerprint enrollment. This call warms up the fingerprint hardware
* and starts scanning for fingerprints. Progress will be indicated by callbacks to the
* {@link EnrollmentCallback} object. It terminates when
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
index f701ec3ec367..d84d29292ed5 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -120,6 +120,14 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
}
/**
+ * Returns if sensor type is ultrasonic Udfps
+ * @return true if sensor is ultrasonic Udfps, false otherwise
+ */
+ public boolean isUltrasonicUdfps() {
+ return sensorType == TYPE_UDFPS_ULTRASONIC;
+ }
+
+ /**
* Returns if sensor type is side-FPS
* @return true if sensor is side-fps, false otherwise
*/
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 742fa570bad7..370f097b6850 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -195,6 +195,9 @@ interface IFingerprintService {
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void onUdfpsUiEvent(int event, long requestId, int sensorId);
+ @EnforcePermission("USE_BIOMETRIC_INTERNAL")
+ void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches);
+
// Sets the controller for managing the UDFPS overlay.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void setUdfpsOverlayController(in IUdfpsOverlayController controller);
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 6458534efc9d..f026997bcc57 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -216,3 +216,11 @@ flag {
description: "Allow privileged apps to call bugreport generation without enforcing user consent and delegate it to the calling app instead"
bug: "324046728"
}
+
+flag {
+ name: "get_private_space_settings"
+ namespace: "profile_experiences"
+ description: "Guards a new Private Profile API in LauncherApps"
+ bug: "346294653"
+ is_exported: true
+}
diff --git a/core/java/android/os/vibrator/VibrationConfig.java b/core/java/android/os/vibrator/VibrationConfig.java
index 555a1204c8a7..9c2fb7bccf5e 100644
--- a/core/java/android/os/vibrator/VibrationConfig.java
+++ b/core/java/android/os/vibrator/VibrationConfig.java
@@ -70,7 +70,7 @@ public class VibrationConfig {
private final boolean mDefaultKeyboardVibrationEnabled;
- private final boolean mHasFixedKeyboardAmplitude;
+ private final boolean mKeyboardVibrationSettingsSupported;
/** @hide */
public VibrationConfig(@Nullable Resources resources) {
@@ -89,8 +89,8 @@ public class VibrationConfig {
com.android.internal.R.bool.config_ignoreVibrationsOnWirelessCharger, false);
mDefaultKeyboardVibrationEnabled = loadBoolean(resources,
com.android.internal.R.bool.config_defaultKeyboardVibrationEnabled, true);
- mHasFixedKeyboardAmplitude = loadFloat(resources,
- com.android.internal.R.dimen.config_keyboardHapticFeedbackFixedAmplitude, -1) > 0;
+ mKeyboardVibrationSettingsSupported = loadBoolean(resources,
+ com.android.internal.R.bool.config_keyboardVibrationSettingsSupported, false);
mDefaultAlarmVibrationIntensity = loadDefaultIntensity(resources,
com.android.internal.R.integer.config_defaultAlarmVibrationIntensity);
@@ -202,11 +202,11 @@ public class VibrationConfig {
}
/**
- * Whether the device has a fixed amplitude for keyboard.
+ * Whether the device support keyboard vibration settings.
* @hide
*/
- public boolean hasFixedKeyboardAmplitude() {
- return mHasFixedKeyboardAmplitude;
+ public boolean isKeyboardVibrationSettingsSupported() {
+ return mKeyboardVibrationSettingsSupported;
}
/** Get the default vibration intensity for given usage. */
@@ -249,6 +249,7 @@ public class VibrationConfig {
+ ", mDefaultNotificationIntensity=" + mDefaultNotificationVibrationIntensity
+ ", mDefaultRingIntensity=" + mDefaultRingVibrationIntensity
+ ", mDefaultKeyboardVibrationEnabled=" + mDefaultKeyboardVibrationEnabled
+ + ", mKeyboardVibrationSettingsSupported=" + mKeyboardVibrationSettingsSupported
+ "}";
}
diff --git a/core/java/android/os/vibrator/persistence/ParsedVibration.java b/core/java/android/os/vibrator/persistence/ParsedVibration.java
index 74d3a7b799e7..19162699a2ef 100644
--- a/core/java/android/os/vibrator/persistence/ParsedVibration.java
+++ b/core/java/android/os/vibrator/persistence/ParsedVibration.java
@@ -38,7 +38,6 @@ import java.util.Objects;
*
* @hide
*/
-@TestApi // This was used in CTS before the flag was introduced.
@SystemApi
@FlaggedApi(FLAG_VIBRATION_XML_APIS)
public final class ParsedVibration {
@@ -62,7 +61,6 @@ public final class ParsedVibration {
*
* @hide
*/
- @TestApi // This was used in CTS before the flag was introduced.
@SystemApi
@FlaggedApi(FLAG_VIBRATION_XML_APIS)
@Nullable
diff --git a/core/java/android/os/vibrator/persistence/VibrationXmlParser.java b/core/java/android/os/vibrator/persistence/VibrationXmlParser.java
index e2312e0c96c4..7d9624c25c12 100644
--- a/core/java/android/os/vibrator/persistence/VibrationXmlParser.java
+++ b/core/java/android/os/vibrator/persistence/VibrationXmlParser.java
@@ -121,7 +121,6 @@ import java.util.List;
*
* @hide
*/
-@TestApi // This was used in CTS before the flag was introduced.
@SystemApi
@FlaggedApi(FLAG_VIBRATION_XML_APIS)
public final class VibrationXmlParser {
@@ -195,7 +194,6 @@ public final class VibrationXmlParser {
*
* @hide
*/
- @TestApi // Replacing test APIs used in CTS before the flagged system APIs was introduced.
@SystemApi
@FlaggedApi(FLAG_VIBRATION_XML_APIS)
@NonNull
@@ -217,7 +215,6 @@ public final class VibrationXmlParser {
*
* @hide
*/
- @TestApi // Replacing test APIs used in CTS before the flagged system APIs was introduced.
@SystemApi
@FlaggedApi(FLAG_VIBRATION_XML_APIS)
@NonNull
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 94c769293bff..c954cdb270e8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6178,6 +6178,15 @@ public final class Settings {
public static final String POINTER_FILL_STYLE = "pointer_fill_style";
/**
+ * Pointer stroke style, specified by
+ * {@link android.view.PointerIcon.PointerIconVectorStyleStroke} constants.
+ *
+ * @hide
+ */
+ @Readable
+ public static final String POINTER_STROKE_STYLE = "pointer_stroke_style";
+
+ /**
* Whether lock-to-app will be triggered by long-press on recents.
* @hide
*/
@@ -6380,6 +6389,7 @@ public final class Settings {
PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME);
PRIVATE_SETTINGS.add(POINTER_SPEED);
PRIVATE_SETTINGS.add(POINTER_FILL_STYLE);
+ PRIVATE_SETTINGS.add(POINTER_STROKE_STYLE);
PRIVATE_SETTINGS.add(POINTER_SCALE);
PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED);
PRIVATE_SETTINGS.add(EGG_MODE);
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index c30212657c57..15351453a151 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -193,6 +193,25 @@ public final class PointerIcon implements Parcelable {
/** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_END =
POINTER_ICON_VECTOR_STYLE_FILL_BLUE;
+ /** @hide */
+ @IntDef(prefix = {"POINTER_ICON_VECTOR_STYLE_STROKE_"}, value = {
+ POINTER_ICON_VECTOR_STYLE_STROKE_WHITE,
+ POINTER_ICON_VECTOR_STYLE_STROKE_BLACK,
+ POINTER_ICON_VECTOR_STYLE_STROKE_NONE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PointerIconVectorStyleStroke {}
+
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_STROKE_WHITE = 0;
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_STROKE_BLACK = 1;
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_STROKE_NONE = 2;
+
+ // If adding PointerIconVectorStyleStroke, update END value for {@link SystemSettingsValidators}
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_STROKE_BEGIN =
+ POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_STROKE_END =
+ POINTER_ICON_VECTOR_STYLE_STROKE_NONE;
+
/** @hide */ public static final float DEFAULT_POINTER_SCALE = 1f;
/** @hide */ public static final float LARGE_POINTER_SCALE = 2.5f;
@@ -712,6 +731,23 @@ public final class PointerIcon implements Parcelable {
}
/**
+ * Convert stroke style constant to resource ID.
+ *
+ * @hide
+ */
+ public static int vectorStrokeStyleToResource(@PointerIconVectorStyleStroke int strokeStyle) {
+ return switch (strokeStyle) {
+ case POINTER_ICON_VECTOR_STYLE_STROKE_BLACK ->
+ com.android.internal.R.style.PointerIconVectorStyleStrokeBlack;
+ case POINTER_ICON_VECTOR_STYLE_STROKE_WHITE ->
+ com.android.internal.R.style.PointerIconVectorStyleStrokeWhite;
+ case POINTER_ICON_VECTOR_STYLE_STROKE_NONE ->
+ com.android.internal.R.style.PointerIconVectorStyleStrokeNone;
+ default -> com.android.internal.R.style.PointerIconVectorStyleStrokeWhite;
+ };
+ }
+
+ /**
* Sets whether drop shadow will draw in the native code.
*
* @hide
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 766e02bf3198..47669427cb9d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13859,11 +13859,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
})
@ResolvedLayoutDir
public int getLayoutDirection() {
- final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
- if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
- mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
- return LAYOUT_DIRECTION_RESOLVED_DEFAULT;
- }
return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ==
PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
}
diff --git a/core/java/android/view/ViewTraversalTracingStrings.java b/core/java/android/view/ViewTraversalTracingStrings.java
index 7dde87bad26e..e95205b79c56 100644
--- a/core/java/android/view/ViewTraversalTracingStrings.java
+++ b/core/java/android/view/ViewTraversalTracingStrings.java
@@ -58,6 +58,6 @@ class ViewTraversalTracingStrings {
out.append(" ");
out.append(className);
v.appendId(out);
- return out.substring(0, Math.min(out.length() - 1, Trace.MAX_SECTION_NAME_LEN - 1));
+ return out.substring(0, Math.min(out.length(), Trace.MAX_SECTION_NAME_LEN));
}
}
diff --git a/core/java/android/webkit/WebViewUpdateManager.java b/core/java/android/webkit/WebViewUpdateManager.java
index 07576a2e89e4..dd48df975906 100644
--- a/core/java/android/webkit/WebViewUpdateManager.java
+++ b/core/java/android/webkit/WebViewUpdateManager.java
@@ -101,6 +101,8 @@ public final class WebViewUpdateManager {
* enabled for all users.
*/
@SuppressLint({"ParcelableList", "ArrayReturn"})
+ @RequiresPermission(allOf = {android.Manifest.permission.INTERACT_ACROSS_USERS,
+ android.Manifest.permission.QUERY_ALL_PACKAGES})
public @NonNull WebViewProviderInfo[] getValidWebViewPackages() {
try {
return mService.getValidWebViewPackages();
diff --git a/core/java/android/window/TaskFragmentAnimationParams.java b/core/java/android/window/TaskFragmentAnimationParams.java
index 85e96c9c0290..67b22f9eb9c8 100644
--- a/core/java/android/window/TaskFragmentAnimationParams.java
+++ b/core/java/android/window/TaskFragmentAnimationParams.java
@@ -171,7 +171,7 @@ public final class TaskFragmentAnimationParams implements Parcelable {
*/
public boolean hasOverrideAnimation() {
return mOpenAnimationResId != DEFAULT_ANIMATION_RESOURCES_ID
- || mChangeAnimationResId != DEFAULT_ANIMATION_BACKGROUND_COLOR
+ || mChangeAnimationResId != DEFAULT_ANIMATION_RESOURCES_ID
|| mCloseAnimationResId != DEFAULT_ANIMATION_RESOURCES_ID;
}
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 5b99ff9703e0..cc880e182b2b 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
@@ -113,4 +113,12 @@ flag {
namespace: "large_screen_experiences_app_compat"
description: "Enables sysui animation for user aspect ratio button"
bug: "300357441"
+}
+
+flag {
+ name: "app_compat_ui_framework"
+ namespace: "large_screen_experiences_app_compat"
+ description: "Whether the declarative compat UI framework is enabled"
+ bug: "270361630"
+ is_fixed_read_only: true
} \ No newline at end of file
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index d0ab674a0e62..1c7acd4ea9af 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -127,3 +127,10 @@ flag {
description: "Whether to show developer option for enabling desktop windowing mode"
bug: "348193756"
}
+
+flag {
+ name: "enable_desktop_windowing_app_to_web"
+ namespace: "lse_desktop_experience"
+ description: "Whether to enable the app-to-web feature and show the open in browser button in the header menu"
+ bug: "349695493"
+}
diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto
index 6a0ec1dcb3f2..e5ced2521134 100644
--- a/core/proto/android/providers/settings/system.proto
+++ b/core/proto/android/providers/settings/system.proto
@@ -126,6 +126,7 @@ message SystemSettingsProto {
option (android.msg_privacy).dest = DEST_EXPLICIT;
optional SettingProto pointer_fill_style = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto pointer_stroke_style = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto pointer_scale = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Pointer pointer = 37;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f61b6bf3f861..9f00d5e08bbf 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -843,6 +843,7 @@
<protected-broadcast android:name="android.intent.action.PROFILE_UNAVAILABLE" />
<protected-broadcast android:name="android.app.action.CONSOLIDATED_NOTIFICATION_POLICY_CHANGED" />
<protected-broadcast android:name="android.intent.action.MAIN_USER_LOCKSCREEN_KNOWLEDGE_FACTOR_CHANGED" />
+ <protected-broadcast android:name="com.android.uwb.uwbcountrycode.GEOCODE_RETRY" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
diff --git a/core/res/res/drawable/pointer_alias_vector.xml b/core/res/res/drawable/pointer_alias_vector.xml
index 035a099cf632..60149f1f26ae 100644
--- a/core/res/res/drawable/pointer_alias_vector.xml
+++ b/core/res/res/drawable/pointer_alias_vector.xml
@@ -22,10 +22,10 @@
android:fillColor="#00FFFFFF"
android:pathData="M14.494 12.779a5.2 5.2 0 0 1-1.771 1.414 5.2 5.2 0 0 1-1.68.489l.81 1.658a1.968 1.968 0 0 0 3.536-1.728zM12.03 8.291l-.81-1.658a1.968 1.968 0 0 0-3.536 1.728l.896 1.833a5.2 5.2 0 0 1 1.77-1.414 5.2 5.2 0 0 1 1.68-.489" />
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="m18.323 13.178-.975-1.995a5.2 5.2 0 0 0-1.704-1.978 5.2 5.2 0 0 0-.517-2.01L14.152 5.2a5.232 5.232 0 0 0-9.401 4.594l.975 1.995a5.2 5.2 0 0 0 1.704 1.978 5.2 5.2 0 0 0 .517 2.01l.975 1.995a5.233 5.233 0 0 0 9.401-4.594m-2.843 6.1a4.23 4.23 0 0 1-5.66-1.944l-.975-1.995a4.2 4.2 0 0 1-.431-1.838l-.001-.276-.234-.146a4.2 4.2 0 0 1-1.555-1.729L5.65 9.355a4.232 4.232 0 1 1 7.604-3.716l.975 1.995c.29.594.428 1.22.431 1.838l.001.276.234.146c.648.405 1.194.99 1.555 1.728l.975 1.995a4.234 4.234 0 0 1-1.945 5.661" />
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="M15.313 12.177a3 3 0 0 0-.416-.633l-.459-.534-.353.609a4.2 4.2 0 0 1-1.801 1.675 4.2 4.2 0 0 1-1.977.429l-.704-.02.213.671q.066.208.164.409l.975 1.995a2.967 2.967 0 1 0 5.332-2.606zm-.827 5.066a1.97 1.97 0 0 1-2.632-.904l-.81-1.658a5.2 5.2 0 0 0 1.68-.489 5.2 5.2 0 0 0 1.771-1.414l.896 1.833a1.97 1.97 0 0 1-.905 2.632m-3.697-7.565a4.2 4.2 0 0 1 1.977-.429l.704.02-.213-.671a3 3 0 0 0-.164-.409l-.975-1.995A2.967 2.967 0 1 0 6.785 8.8l.975 1.995q.172.35.416.633l.459.534.353-.609a4.2 4.2 0 0 1 1.801-1.675m-2.21.516-.895-1.833a1.968 1.968 0 1 1 3.536-1.728l.81 1.658a5.2 5.2 0 0 0-1.68.489 5.2 5.2 0 0 0-1.771 1.414m3.151 1.965a3 3 0 0 0 1.02-.818l.755-.95-1.205.142a2.97 2.97 0 0 0-1.975 1.1l-.755.95 1.205-.142c.324-.039.646-.132.955-.282" />
<path
android:fillColor="?attr/pointerIconVectorFill"
diff --git a/core/res/res/drawable/pointer_all_scroll_vector.xml b/core/res/res/drawable/pointer_all_scroll_vector.xml
index 45ad98c1b57c..41314ed7e3a4 100644
--- a/core/res/res/drawable/pointer_all_scroll_vector.xml
+++ b/core/res/res/drawable/pointer_all_scroll_vector.xml
@@ -24,5 +24,5 @@
android:fillColor="?attr/pointerIconVectorFill"/>
<path
android:pathData="M12 4c.36 0 .72.18.93.54l1.75 3.06c.41.71-.1 1.6-.92 1.6h-.82v1.86h1.86v-.84a1.07 1.07 0 0 1 1.6-.92l3.06 1.75c.72.41.72 1.44 0 1.85l-3.06 1.76a1.07 1.07 0 0 1-1.6-.92v-.8h-1.86v1.87h.82c.82 0 1.33.88.92 1.6l-1.75 3.06a1.07 1.07 0 0 1-1.85 0L9.32 16.4c-.4-.7.1-1.6.93-1.6h.81v-1.86H9.2v.8a1.07 1.07 0 0 1-1.6.92L4.54 12.9a1.06 1.06 0 0 1 0-1.85L7.6 9.3a1.07 1.07 0 0 1 1.6.92v.85h1.86V9.2h-.82c-.81 0-1.33-.89-.92-1.6l1.76-3.06c.2-.36.56-.54.92-.54m0-1c-.74 0-1.41.39-1.79 1.04L8.45 7.1c-.18.33-.28.7-.27 1.05h-.05c-.36 0-.71.1-1.03.28l-3.06 1.76a2.05 2.05 0 0 0 0 3.58l3.06 1.75c.32.18.67.28 1.03.28h.05c-.01.38.08.76.28 1.1l1.75 3.07c.38.65 1.05 1.03 1.8 1.03s1.41-.38 1.78-1.03l1.76-3.07c.2-.34.3-.72.28-1.1h.04c.36 0 .71-.1 1.03-.28l3.06-1.75a2.07 2.07 0 0 0 0-3.58L16.9 8.43a2.07 2.07 0 0 0-1.03-.28h-.04c0-.36-.09-.72-.28-1.05L13.8 4.04A2.04 2.04 0 0 0 12 3z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="?attr/pointerIconVectorStroke"/>
</vector>
diff --git a/core/res/res/drawable/pointer_arrow_vector.xml b/core/res/res/drawable/pointer_arrow_vector.xml
index 2614170f6994..a0bd5b614280 100644
--- a/core/res/res/drawable/pointer_arrow_vector.xml
+++ b/core/res/res/drawable/pointer_arrow_vector.xml
@@ -24,5 +24,5 @@
android:fillColor="?attr/pointerIconVectorFill"/>
<path
android:pathData="M16.94 10.38 7.37 3.22a2.77 2.77 0 0 0-2.93-.27 2.75 2.75 0 0 0-1.55 2.51l.01 11.95a2.78 2.78 0 0 0 2.82 2.8c.77 0 1.5-.32 2.03-.9l2.97-3.19a.8.8 0 0 1 .5-.25l4.34-.46a2.76 2.76 0 0 0 2.4-2.05 2.8 2.8 0 0 0-1.02-2.98zM17 13.1a1.77 1.77 0 0 1-1.55 1.31l-4.33.47a1.8 1.8 0 0 0-1.13.56l-2.97 3.2c-.4.42-.86.57-1.3.57-.24 0-.48-.05-.68-.13a1.77 1.77 0 0 1-1.14-1.67V5.46a1.81 1.81 0 0 1 1.8-1.8c.38 0 .75.11 1.07.36l9.57 7.16c.72.54.81 1.35.66 1.92z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="?attr/pointerIconVectorStroke"/>
</vector>
diff --git a/core/res/res/drawable/pointer_cell_vector.xml b/core/res/res/drawable/pointer_cell_vector.xml
index cead1c4185b4..9ad64e27da63 100644
--- a/core/res/res/drawable/pointer_cell_vector.xml
+++ b/core/res/res/drawable/pointer_cell_vector.xml
@@ -19,7 +19,7 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="M19 9.667h-4.668V5a2 2 0 0 0-2-2h-.667a2 2 0 0 0-2 2v4.667H5a2 2 0 0 0-2 2v.667a2 2 0 0 0 2 2h4.665V19a2 2 0 0 0 2 2h.667a2 2 0 0 0 2-2v-4.666H19a2 2 0 0 0 2-2v-.667a2 2 0 0 0-2-2m1 2.667a1 1 0 0 1-1 1h-5.668V19a1 1 0 0 1-1 1h-.667a1 1 0 0 1-1-1v-5.666H5a1 1 0 0 1-1-1v-.667a1 1 0 0 1 1-1h5.665V5a1 1 0 0 1 1-1h.667a1 1 0 0 1 1 1v5.667H19a1 1 0 0 1 1 1z" />
<path
android:fillColor="?attr/pointerIconVectorFill"
diff --git a/core/res/res/drawable/pointer_context_menu_vector.xml b/core/res/res/drawable/pointer_context_menu_vector.xml
index fb2af431ffb6..33b1acefc827 100644
--- a/core/res/res/drawable/pointer_context_menu_vector.xml
+++ b/core/res/res/drawable/pointer_context_menu_vector.xml
@@ -19,11 +19,11 @@
android:viewportHeight="24"
android:viewportWidth="24">
<group>
- <path android:fillColor="#FFFFFF" android:pathData="M19.475 2.604h-2.66c-.842 0-1.527.685-1.527 1.527v2.66c0 .842.685 1.527 1.527 1.527h2.66c.842 0 1.527-.685 1.527-1.527v-2.66c0-.842-.685-1.527-1.527-1.527m.67 4.187c0 .37-.3.67-.67.67h-2.66a.67.67 0 0 1-.67-.67v-2.66c0-.37.3-.67.67-.67h2.66c.37 0 .67.3.67.67z" />
- <path android:fillColor="#FFFFFF" android:pathData="M19.175 4.17h-2.067a.3.3 0 1 0 0 .6h2.067a.3.3 0 1 0 0-.6m0 .886h-2.067a.3.3 0 1 0 0 .6h2.067a.3.3 0 1 0 0-.6m0 .868h-2.067a.3.3 0 1 0 0 .6h2.067a.3.3 0 1 0 0-.6" />
+ <path android:fillColor="?attr/pointerIconVectorStroke" android:pathData="M19.475 2.604h-2.66c-.842 0-1.527.685-1.527 1.527v2.66c0 .842.685 1.527 1.527 1.527h2.66c.842 0 1.527-.685 1.527-1.527v-2.66c0-.842-.685-1.527-1.527-1.527m.67 4.187c0 .37-.3.67-.67.67h-2.66a.67.67 0 0 1-.67-.67v-2.66c0-.37.3-.67.67-.67h2.66c.37 0 .67.3.67.67z" />
+ <path android:fillColor="?attr/pointerIconVectorStroke" android:pathData="M19.175 4.17h-2.067a.3.3 0 1 0 0 .6h2.067a.3.3 0 1 0 0-.6m0 .886h-2.067a.3.3 0 1 0 0 .6h2.067a.3.3 0 1 0 0-.6m0 .868h-2.067a.3.3 0 1 0 0 .6h2.067a.3.3 0 1 0 0-.6" />
</group>
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="M16.938 10.38 7.372 3.216a2.77 2.77 0 0 0-2.931-.262A2.75 2.75 0 0 0 2.894 5.46l.009 11.951a2.785 2.785 0 0 0 1.776 2.604c.33.129.691.197 1.044.197a2.75 2.75 0 0 0 2.031-.897l2.969-3.193a.8.8 0 0 1 .5-.25l4.336-.467c1.397-.15 2.157-1.153 2.401-2.041a2.785 2.785 0 0 0-1.022-2.984m.058 2.718c-.157.571-.645 1.216-1.544 1.312l-4.335.467a1.8 1.8 0 0 0-1.126.563l-2.97 3.193a1.74 1.74 0 0 1-1.298.578 1.9 1.9 0 0 1-.678-.128c-.551-.217-1.141-.771-1.142-1.674l-.009-11.95c0-.697.371-1.299.994-1.611.262-.131.538-.196.813-.196.377 0 .75.123 1.072.365l9.566 7.163c.723.542.814 1.346.657 1.918" />
<path
android:fillColor="?attr/pointerIconVectorFill"
diff --git a/core/res/res/drawable/pointer_copy_vector.xml b/core/res/res/drawable/pointer_copy_vector.xml
index 3f138685e6eb..8ac8c2181ed5 100644
--- a/core/res/res/drawable/pointer_copy_vector.xml
+++ b/core/res/res/drawable/pointer_copy_vector.xml
@@ -23,7 +23,7 @@
<path android:fillColor="?attr/pointerIconVectorFillInverse" android:pathData="M19.299 6H18V4.7a.5.5 0 0 0-1 0V6h-1.301a.5.5 0 0 0 0 1H17v1.3a.5.5 0 0 0 1 0V7h1.299a.5.5 0 0 0 0-1" />
</group>
<path
- android:fillColor="#000000"
+ android:fillColor="?attr/pointerIconVectorStrokeInverse"
android:pathData="M18.485 10.884v1.739q.013.189.013.38c0 3.045-2.518 5.514-5.563 5.514a5.58 5.58 0 0 1-3.922-1.613 1 1 0 0 1-.117-.106l-3.847-3.936c-.482-.494-.482-1.294 0-1.787s1.265-.494 1.747 0l.697.713V7.583a1 1 0 0 1 2 0v1.096q.463-.364.997-.625v-1.57a1 1 0 0 1 2 0v1.022q.22-.018.446-.018c.062 0 .123.007.185.009A4.4 4.4 0 0 1 13 6.5c0-.378.061-.739.149-1.09a1.97 1.97 0 0 0-1.659-.926c-.903 0-1.658.603-1.906 1.425a1.997 1.997 0 0 0-3.091 1.674v2.206a2.2 2.2 0 0 0-2.159.586 2.285 2.285 0 0 0 0 3.185l3.847 3.936q.063.061.13.118l-.001.001a6.58 6.58 0 0 0 4.624 1.902c3.586 0 6.563-2.905 6.563-6.514q-.001-.192-.013-.381v-2.108c-.316.156-.645.29-.999.37" />
<path
android:fillColor="#1FA54A"
diff --git a/core/res/res/drawable/pointer_crosshair_vector.xml b/core/res/res/drawable/pointer_crosshair_vector.xml
index 8a50d1bdd497..4fba08076e7a 100644
--- a/core/res/res/drawable/pointer_crosshair_vector.xml
+++ b/core/res/res/drawable/pointer_crosshair_vector.xml
@@ -19,7 +19,7 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="M19.25 10.25h-5.5v-5.5a1.75 1.75 0 0 0-3.5 0v5.5h-5.5a1.75 1.75 0 0 0 0 3.5h5.5v5.5a1.75 1.75 0 0 0 3.5 0v-5.5h5.5a1.75 1.75 0 0 0 0-3.5m0 2.5h-6.5v6.5a.75.75 0 0 1-1.5 0v-6.5h-6.5a.75.75 0 0 1 0-1.5h6.5v-6.5a.75.75 0 0 1 1.5 0v6.5h6.5a.75.75 0 0 1 0 1.5" />
<path
android:fillType="evenOdd"
diff --git a/core/res/res/drawable/pointer_grab_vector.xml b/core/res/res/drawable/pointer_grab_vector.xml
index 48c01ceb6588..d9e1f18919fa 100644
--- a/core/res/res/drawable/pointer_grab_vector.xml
+++ b/core/res/res/drawable/pointer_grab_vector.xml
@@ -19,7 +19,7 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
- android:fillColor="#000000"
+ android:fillColor="?attr/pointerIconVectorStrokeInverse"
android:pathData="M20.442 7.562a2 2 0 0 0-2-2c-.366 0-.705.106-1 .277V4.686a2 2 0 0 0-2-2 2 2 0 0 0-1.004.279 1.995 1.995 0 0 0-3.986-.06 2 2 0 0 0-1.006-.28 2 2 0 0 0-2 2v6.501l-.247-.253a2.216 2.216 0 0 0-3.178 0 2.286 2.286 0 0 0 0 3.186l5.106 5.224q.063.061.131.118l-.001.001a6.58 6.58 0 0 0 4.624 1.901c3.587 0 6.565-2.906 6.565-6.516q0-.105-.004-.21m-6.561 5.727a5.58 5.58 0 0 1-3.922-1.613 1 1 0 0 1-.117-.106l-5.106-5.224a1.286 1.286 0 0 1 0-1.788 1.215 1.215 0 0 1 1.747 0l1.962 2.008V4.625a1 1 0 0 1 2 0v5.833q.463-.362.996-.623V3a1 1 0 0 1 2 0v6.29a6 6 0 0 1 1 .011V4.686a1 1 0 0 1 2 0v5.21c.357.185.693.408 1 .663V7.562a1 1 0 0 1 2 0v7.019h.001-.001q.004.104.004.207c.001 3.046-2.518 5.516-5.564 5.516" />
<path
android:fillColor="?attr/pointerIconVectorFillInverse"
diff --git a/core/res/res/drawable/pointer_grabbing_vector.xml b/core/res/res/drawable/pointer_grabbing_vector.xml
index ad9f86c1848c..7f52fc5f42ba 100644
--- a/core/res/res/drawable/pointer_grabbing_vector.xml
+++ b/core/res/res/drawable/pointer_grabbing_vector.xml
@@ -19,7 +19,7 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
- android:fillColor="#000000"
+ android:fillColor="?attr/pointerIconVectorStrokeInverse"
android:pathData="M19.485 12.622V8.508a2 2 0 0 0-3.12-1.657 1.993 1.993 0 0 0-2.99-1.006 1.99 1.99 0 0 0-1.886-1.361c-.903 0-1.658.603-1.906 1.425a2 2 0 0 0-3.09 1.674v2.206a2.2 2.2 0 0 0-2.159.586 2.285 2.285 0 0 0 0 3.185l3.847 3.936q.063.061.13.118l-.001.001a6.58 6.58 0 0 0 4.624 1.902c3.586 0 6.563-2.905 6.563-6.514a5 5 0 0 0-.012-.381m-6.55 5.895a5.58 5.58 0 0 1-3.922-1.613 1 1 0 0 1-.117-.106l-3.847-3.936c-.482-.494-.482-1.294 0-1.787s1.265-.494 1.747 0l.697.713V7.583a1 1 0 0 1 2 0v1.096q.463-.364.997-.625v-1.57a1 1 0 0 1 2 0v1.022a5.5 5.5 0 0 1 .996.009v-.007a1 1 0 0 1 2 0v.599q.537.277 1 .66v-.259a1 1 0 0 1 2 0v4.115q.013.189.013.38c-.001 3.045-2.518 5.514-5.564 5.514" />
<path
android:fillColor="?attr/pointerIconVectorFillInverse"
diff --git a/core/res/res/drawable/pointer_hand_vector.xml b/core/res/res/drawable/pointer_hand_vector.xml
index a06dc08b8b3f..115b53b5d495 100644
--- a/core/res/res/drawable/pointer_hand_vector.xml
+++ b/core/res/res/drawable/pointer_hand_vector.xml
@@ -19,7 +19,7 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
- android:fillColor="#000000"
+ android:fillColor="?attr/pointerIconVectorStrokeInverse"
android:pathData="M20.492 15.197v-4.198A1.995 1.995 0 0 0 18.5 9.001c-.413 0-.797.126-1.115.342a1.99 1.99 0 0 0-1.873-1.341c-.411 0-.792.125-1.109.339a1.99 1.99 0 0 0-1.879-1.361c-.363 0-.699.105-.992.275V3.998A1.99 1.99 0 0 0 9.542 2c-1.1 0-1.992.895-1.992 1.998v7.831l-.242-.249a2.2 2.2 0 0 0-3.164 0 2.29 2.29 0 0 0 0 3.183l5.084 5.219q.063.061.13.118l-.001.001A6.54 6.54 0 0 0 13.963 22c3.572 0 6.537-2.903 6.537-6.509q0-.148-.008-.294m-6.529 5.804a5.55 5.55 0 0 1-3.906-1.611 1 1 0 0 1-.117-.106l-5.084-5.219a1.286 1.286 0 0 1 0-1.786 1.21 1.21 0 0 1 1.74 0l1.95 2.002V3.998c0-.552.446-.999.996-.999s.996.447.996.999v7.17l.011-.007a.495.495 0 0 0 .989-.037V8.939a.992.992 0 0 1 1.984.039v.796l-.007 1.386a.5.5 0 0 0 .495.502h.003a.5.5 0 0 0 .498-.497l.006-1.157h.001V10a.997.997 0 1 1 1.991 0v.601l.004.003v1.02q.001.107.042.199a.5.5 0 0 0 .153.187l.031.021a.5.5 0 0 0 .231.083c.014.001.026.008.04.008a.5.5 0 0 0 .498-.5v-.642a.996.996 0 0 1 .993-.98c.55 0 .996.447.996.999v4.199a6 6 0 0 1 .008.293c-.001 3.043-2.509 5.51-5.542 5.51" />
<path
android:fillColor="?attr/pointerIconVectorFillInverse"
diff --git a/core/res/res/drawable/pointer_handwriting_vector.xml b/core/res/res/drawable/pointer_handwriting_vector.xml
index 849759291101..6f62abaca7aa 100644
--- a/core/res/res/drawable/pointer_handwriting_vector.xml
+++ b/core/res/res/drawable/pointer_handwriting_vector.xml
@@ -19,8 +19,8 @@
android:viewportHeight="24"
android:viewportWidth="24">
<group>
- <path android:fillColor="#FFFFFF" android:pathData="M20.12 6.8 18.7 5.38c-.57-.57-1.32-.88-2.12-.88s-1.56.31-2.13.88l-7.16 7.16-.29.29V5c0-1.1-.9-2-2-2s-2 .9-2 2v14c0 1.1.9 2 2 2s2-.9 2-2v-.5h5.67l.29-.29 7.16-7.16c.57-.57.88-1.32.88-2.12s-.31-1.57-.88-2.13M6 19c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55.45-1 1-1s1 .45 1 1zm13.41-8.66-7.16 7.16H8v-4.25l7.16-7.16c.39-.39.9-.59 1.41-.59h.01c.51 0 1.02.2 1.41.59l1.42 1.42c.78.78.78 2.05 0 2.83" />
- <path android:fillColor="#FFFFFF" android:pathData="m16.431 7.64-6.29 6.29 1.43 1.43 6.29-6.29-1.42-1.43z" />
+ <path android:fillColor="?attr/pointerIconVectorStroke" android:pathData="M20.12 6.8 18.7 5.38c-.57-.57-1.32-.88-2.12-.88s-1.56.31-2.13.88l-7.16 7.16-.29.29V5c0-1.1-.9-2-2-2s-2 .9-2 2v14c0 1.1.9 2 2 2s2-.9 2-2v-.5h5.67l.29-.29 7.16-7.16c.57-.57.88-1.32.88-2.12s-.31-1.57-.88-2.13M6 19c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55.45-1 1-1s1 .45 1 1zm13.41-8.66-7.16 7.16H8v-4.25l7.16-7.16c.39-.39.9-.59 1.41-.59h.01c.51 0 1.02.2 1.41.59l1.42 1.42c.78.78.78 2.05 0 2.83" />
+ <path android:fillColor="?attr/pointerIconVectorStroke" android:pathData="m16.431 7.64-6.29 6.29 1.43 1.43 6.29-6.29-1.42-1.43z" />
</group>
<path
android:fillColor="?attr/pointerIconVectorFill"
diff --git a/core/res/res/drawable/pointer_help_vector.xml b/core/res/res/drawable/pointer_help_vector.xml
index 07970fbdd67a..63cf287080aa 100644
--- a/core/res/res/drawable/pointer_help_vector.xml
+++ b/core/res/res/drawable/pointer_help_vector.xml
@@ -22,7 +22,7 @@
android:fillColor="?attr/pointerIconVectorFill"
android:pathData="M16.339 11.18 6.773 4.017a1.78 1.78 0 0 0-1.072-.365c-.274 0-.551.065-.813.196a1.77 1.77 0 0 0-.994 1.611l.009 11.951c0 .903.59 1.457 1.142 1.674.2.078.433.128.678.128.434 0 .906-.155 1.298-.578l2.97-3.193a1.8 1.8 0 0 1 1.126-.563l4.335-.467c.899-.097 1.387-.741 1.544-1.312.157-.573.066-1.377-.657-1.919" />
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="M16.94 10.38 7.37 3.22a2.77 2.77 0 0 0-2.93-.27A2.75 2.75 0 0 0 2.9 5.46l.01 11.95a2.79 2.79 0 0 0 2.82 2.8c.78 0 1.5-.32 2.03-.9l2.97-3.19a.8.8 0 0 1 .5-.25l4.34-.46a2.76 2.76 0 0 0 2.4-2.05 2.8 2.8 0 0 0-1.02-2.98zM17 13.1a1.77 1.77 0 0 1-1.55 1.31l-4.33.47a1.8 1.8 0 0 0-1.13.56l-2.97 3.2c-.4.42-.86.57-1.3.57-.24 0-.48-.05-.68-.13a1.77 1.77 0 0 1-1.14-1.67V5.46a1.81 1.81 0 0 1 1.8-1.8c.38 0 .75.11 1.07.36l9.57 7.16c.72.54.81 1.35.66 1.92zm2.64-10.83a2.5 2.5 0 0 0-1.84-.72 3 3 0 0 0-2.83 1.93l-.39.94.96.37.86.32.12.05-.02.03c-.22.4-.3.82-.3 1.33v.94a1.56 1.56 0 0 0 .4 1.47 1.54 1.54 0 0 0 2.24.01 1.55 1.55 0 0 0 .28-1.84v-.52c0-.1.02-.17.03-.25l.16-.15c.32-.25.6-.56.78-.93.18-.37.26-.76.26-1.16 0-.68-.21-1.32-.7-1.82zm-1.5 5.96a.55.55 0 0 1-.82 0 .56.56 0 0 1-.17-.4c0-.16.06-.3.17-.4a.55.55 0 0 1 .41-.18c.15 0 .28.06.4.17a.55.55 0 0 1 0 .81zm1.05-3.42c-.1.22-.28.42-.52.6-.26.22-.42.42-.47.6-.05.18-.08.37-.08.57l-.93-.06c0-.38.07-.62.19-.86.13-.24.3-.46.54-.66.17-.13.3-.28.4-.43s.14-.3.14-.46c0-.2-.08-.37-.22-.5s-.31-.17-.52-.17c-.2 0-.39.06-.56.18-.17.13-.3.31-.4.56l-.87-.33a2.03 2.03 0 0 1 1.91-1.3c.48 0 .86.14 1.13.42.28.28.41.65.41 1.12 0 .26-.05.5-.15.72z" />
<path
android:fillColor="?attr/pointerIconVectorFill"
diff --git a/core/res/res/drawable/pointer_horizontal_double_arrow_vector.xml b/core/res/res/drawable/pointer_horizontal_double_arrow_vector.xml
index 32c56b6aa098..7aa65713dbf0 100644
--- a/core/res/res/drawable/pointer_horizontal_double_arrow_vector.xml
+++ b/core/res/res/drawable/pointer_horizontal_double_arrow_vector.xml
@@ -19,7 +19,7 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="m19.963 10.185-3.065-1.758c-1.327-.761-2.96.14-3.072 1.633h-3.651c-.113-1.492-1.746-2.394-3.072-1.633l-3.065 1.758c-1.383.793-1.383 2.786 0 3.579l3.065 1.758c1.311.752 2.918-.12 3.065-1.581h3.666c.147 1.46 1.754 2.333 3.065 1.581l3.065-1.758c1.382-.793 1.382-2.786-.001-3.579m-.498 2.712L16.4 14.655a1.065 1.065 0 0 1-1.596-.922v-.791H9.195v.791c0 .818-.886 1.33-1.596.922l-3.065-1.758a1.063 1.063 0 0 1 0-1.845l3.065-1.758a1.065 1.065 0 0 1 1.596.922v.843h5.609v-.843c0-.818.886-1.33 1.596-.922l3.065 1.758a1.063 1.063 0 0 1 0 1.845" />
<path
android:fillColor="?attr/pointerIconVectorFill"
diff --git a/core/res/res/drawable/pointer_nodrop_vector.xml b/core/res/res/drawable/pointer_nodrop_vector.xml
index 6108e9681fa5..7cef01af77af 100644
--- a/core/res/res/drawable/pointer_nodrop_vector.xml
+++ b/core/res/res/drawable/pointer_nodrop_vector.xml
@@ -23,7 +23,7 @@
<path android:fillColor="?attr/pointerIconVectorFillInverse" android:pathData="M17.5 4c-.493 0-.95.148-1.337.395l3.442 3.442C19.852 7.45 20 6.993 20 6.5 20 5.121 18.879 4 17.5 4M15 6.5C15 7.879 16.121 9 17.5 9c.525 0 1.011-.164 1.413-.441l-3.472-3.472A2.5 2.5 0 0 0 15 6.5" />
</group>
<path
- android:fillColor="#000000"
+ android:fillColor="?attr/pointerIconVectorStrokeInverse"
android:pathData="M18.485 10.932v1.69q.013.188.013.38c0 3.045-2.518 5.514-5.563 5.514a5.58 5.58 0 0 1-3.922-1.613 1 1 0 0 1-.117-.106l-3.847-3.936c-.482-.494-.482-1.294 0-1.787s1.265-.494 1.747 0l.697.713V7.583a1 1 0 0 1 2 0v1.096q.463-.364.997-.625v-1.57a1 1 0 0 1 2 0v1.022q.22-.018.446-.018c.046 0 .09.006.135.007a4.5 4.5 0 0 1-.117-.995c0-.399.068-.779.165-1.148a1.97 1.97 0 0 0-1.629-.867c-.903 0-1.658.603-1.906 1.425a2 2 0 0 0-1.091-.327 2 2 0 0 0-2 2v2.206a2.2 2.2 0 0 0-2.159.586 2.285 2.285 0 0 0 0 3.185l3.847 3.936q.063.061.13.118l-.001.001a6.58 6.58 0 0 0 4.624 1.902c3.586 0 6.563-2.905 6.563-6.514q-.001-.192-.013-.381v-2.056a4.5 4.5 0 0 1-.999.366" />
<path
android:fillColor="#B22A25"
diff --git a/core/res/res/drawable/pointer_text_vector.xml b/core/res/res/drawable/pointer_text_vector.xml
index a14727309674..2fa133258ac1 100644
--- a/core/res/res/drawable/pointer_text_vector.xml
+++ b/core/res/res/drawable/pointer_text_vector.xml
@@ -22,6 +22,6 @@
android:fillColor="?attr/pointerIconVectorFill"
android:pathData="M12 3c-.551 0-1 .448-1 1v14a1.001 1.001 0 0 0 2 0V4c0-.552-.449-1-1-1" />
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="M12 2c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2s2-.897 2-2V4c0-1.103-.897-2-2-2m1 16a1.001 1.001 0 0 1-2 0V4a1.001 1.001 0 0 1 2 0z" />
</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_vector.xml b/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_vector.xml
index 7f95207d9e82..cd4e5e703fa9 100644
--- a/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_vector.xml
+++ b/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_vector.xml
@@ -19,7 +19,7 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="m18.896 16.365-.924-3.41c-.398-1.467-2.169-1.985-3.305-1.035L12.08 9.333c.952-1.136.434-2.908-1.034-3.306l-3.41-.924c-1.539-.416-2.948.993-2.532 2.532l.924 3.41c.398 1.468 2.17 1.986 3.306 1.034l2.586 2.586c-.953 1.136-.435 2.91 1.033 3.307l3.41.924c1.54.417 2.949-.992 2.533-2.531m-2.27 1.566-3.41-.924a1.065 1.065 0 0 1-.476-1.781l.579-.579-3.966-3.966-.579.579a1.066 1.066 0 0 1-1.781-.476L6.07 7.373a1.063 1.063 0 0 1 1.304-1.304l3.41.924a1.065 1.065 0 0 1 .476 1.781l-.578.578 3.966 3.966.577-.577a1.066 1.066 0 0 1 1.781.477l.924 3.41a1.062 1.062 0 0 1-1.304 1.303" />
<path
android:fillType="evenOdd"
diff --git a/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_vector.xml b/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_vector.xml
index 8a3371524429..3736290c94ad 100644
--- a/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_vector.xml
+++ b/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_vector.xml
@@ -19,7 +19,7 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="m16.365 5.104-3.41.924c-1.468.398-1.986 2.171-1.033 3.307l-2.586 2.586c-1.136-.952-2.909-.434-3.306 1.034l-.924 3.41c-.417 1.539.992 2.948 2.531 2.531l3.41-.924c1.468-.398 1.986-2.17 1.034-3.306l2.587-2.587c1.136.951 2.908.432 3.305-1.035l.924-3.41c.415-1.538-.994-2.947-2.532-2.53m1.565 2.269-.924 3.41a1.065 1.065 0 0 1-1.781.476l-.577-.577-3.966 3.966.578.578a1.066 1.066 0 0 1-.476 1.781l-3.41.924a1.063 1.063 0 0 1-1.304-1.304l.924-3.41a1.066 1.066 0 0 1 1.781-.477l.578.578 3.966-3.966-.579-.579a1.066 1.066 0 0 1 .476-1.781l3.41-.924a1.063 1.063 0 0 1 1.304 1.305" />
<path
android:fillColor="?attr/pointerIconVectorFill"
diff --git a/core/res/res/drawable/pointer_vertical_double_arrow_vector.xml b/core/res/res/drawable/pointer_vertical_double_arrow_vector.xml
index 889372c39433..ff99f4101aab 100644
--- a/core/res/res/drawable/pointer_vertical_double_arrow_vector.xml
+++ b/core/res/res/drawable/pointer_vertical_double_arrow_vector.xml
@@ -19,7 +19,7 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="M13.945 13.829V10.17c1.476-.131 2.363-1.75 1.606-3.069l-1.758-3.065c-.793-1.383-2.786-1.383-3.579 0L8.455 7.102c-.757 1.319.131 2.939 1.607 3.069v3.658c-1.477.13-2.364 1.75-1.607 3.069l1.758 3.065c.793 1.383 2.786 1.383 3.579 0l1.758-3.065c.758-1.319-.129-2.938-1.605-3.069m.739 2.572-1.758 3.065a1.063 1.063 0 0 1-1.845 0l-1.758-3.065a1.065 1.065 0 0 1 .922-1.596h.818v-5.61h-.818c-.818 0-1.33-.886-.922-1.596l1.758-3.065a1.063 1.063 0 0 1 1.845 0l1.758 3.065a1.065 1.065 0 0 1-.922 1.596h-.817v5.609h.817c.817.001 1.329.886.922 1.597" />
<path
android:fillColor="?attr/pointerIconVectorFill"
diff --git a/core/res/res/drawable/pointer_vertical_text_vector.xml b/core/res/res/drawable/pointer_vertical_text_vector.xml
index 9238f94fa808..d610d0488338 100644
--- a/core/res/res/drawable/pointer_vertical_text_vector.xml
+++ b/core/res/res/drawable/pointer_vertical_text_vector.xml
@@ -22,6 +22,6 @@
android:fillColor="?attr/pointerIconVectorFill"
android:pathData="M19 11H5a1 1 0 0 0 0 2h14a1 1 0 0 0 0-2" />
<path
- android:fillColor="#FFFFFF"
+ android:fillColor="?attr/pointerIconVectorStroke"
android:pathData="M19 10H5c-1.103 0-2 .897-2 2s.897 2 2 2h14c1.103 0 2-.897 2-2s-.897-2-2-2m0 3H5a1 1 0 0 1 0-2h14a1 1 0 0 1 0 2" />
</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/pointer_zoom_in_vector.xml b/core/res/res/drawable/pointer_zoom_in_vector.xml
index a7f56c23d5fb..c4aa95bbc384 100644
--- a/core/res/res/drawable/pointer_zoom_in_vector.xml
+++ b/core/res/res/drawable/pointer_zoom_in_vector.xml
@@ -19,8 +19,8 @@
android:viewportHeight="24"
android:viewportWidth="24">
<group>
- <path android:fillColor="#FFFFFF" android:pathData="m20.445 17.298-3.591-3.613a7.5 7.5 0 0 0 1.243-4.138 7.547 7.547 0 1 0-7.546 7.546c1.239 0 2.402-.31 3.435-.84l3.733 3.756a1.922 1.922 0 1 0 2.726-2.711m-.713 2.009a.923.923 0 0 1-1.305-.004l-4.268-4.294a6.547 6.547 0 1 1 2.938-5.462 6.52 6.52 0 0 1-1.555 4.236l4.194 4.22a.92.92 0 0 1-.004 1.304" />
- <path android:fillColor="#FFFFFF" android:pathData="M10.55 5a4.546 4.546 0 1 0 0 9.093 4.546 4.546 0 0 0 0-9.093m2.462 5h-2v2a.5.5 0 0 1-1 0v-2h-2a.5.5 0 0 1 0-1h2V7a.5.5 0 0 1 1 0v2h2a.5.5 0 0 1 0 1" />
+ <path android:fillColor="?attr/pointerIconVectorStroke" android:pathData="m20.445 17.298-3.591-3.613a7.5 7.5 0 0 0 1.243-4.138 7.547 7.547 0 1 0-7.546 7.546c1.239 0 2.402-.31 3.435-.84l3.733 3.756a1.922 1.922 0 1 0 2.726-2.711m-.713 2.009a.923.923 0 0 1-1.305-.004l-4.268-4.294a6.547 6.547 0 1 1 2.938-5.462 6.52 6.52 0 0 1-1.555 4.236l4.194 4.22a.92.92 0 0 1-.004 1.304" />
+ <path android:fillColor="?attr/pointerIconVectorStroke" android:pathData="M10.55 5a4.546 4.546 0 1 0 0 9.093 4.546 4.546 0 0 0 0-9.093m2.462 5h-2v2a.5.5 0 0 1-1 0v-2h-2a.5.5 0 0 1 0-1h2V7a.5.5 0 0 1 1 0v2h2a.5.5 0 0 1 0 1" />
</group>
<group>
<path android:fillColor="?attr/pointerIconVectorFill" android:pathData="m19.736 18.003-4.194-4.22a6.547 6.547 0 1 0-1.382 1.226l4.268 4.294a.923.923 0 0 0 1.308-1.3m-9.186-3.91A4.546 4.546 0 1 1 10.549 5a4.546 4.546 0 0 1 .001 9.093" />
diff --git a/core/res/res/drawable/pointer_zoom_out_vector.xml b/core/res/res/drawable/pointer_zoom_out_vector.xml
index e46b978df5b6..16c4520a8637 100644
--- a/core/res/res/drawable/pointer_zoom_out_vector.xml
+++ b/core/res/res/drawable/pointer_zoom_out_vector.xml
@@ -19,8 +19,8 @@
android:viewportHeight="24"
android:viewportWidth="24">
<group>
- <path android:fillColor="#FFFFFF" android:pathData="m20.445 17.298-3.591-3.613a7.5 7.5 0 0 0 1.243-4.138 7.547 7.547 0 1 0-7.546 7.546c1.239 0 2.402-.31 3.435-.84l3.733 3.756a1.922 1.922 0 1 0 2.726-2.711m-.713 2.009a.923.923 0 0 1-1.305-.004l-4.268-4.294a6.547 6.547 0 1 1 2.938-5.462 6.52 6.52 0 0 1-1.555 4.236l4.194 4.22a.92.92 0 0 1-.004 1.304" />
- <path android:fillColor="#FFFFFF" android:pathData="M10.55 5a4.546 4.546 0 1 0 0 9.093 4.546 4.546 0 0 0 0-9.093m2.462 5h-5a.5.5 0 0 1 0-1h5a.5.5 0 0 1 0 1" />
+ <path android:fillColor="?attr/pointerIconVectorStroke" android:pathData="m20.445 17.298-3.591-3.613a7.5 7.5 0 0 0 1.243-4.138 7.547 7.547 0 1 0-7.546 7.546c1.239 0 2.402-.31 3.435-.84l3.733 3.756a1.922 1.922 0 1 0 2.726-2.711m-.713 2.009a.923.923 0 0 1-1.305-.004l-4.268-4.294a6.547 6.547 0 1 1 2.938-5.462 6.52 6.52 0 0 1-1.555 4.236l4.194 4.22a.92.92 0 0 1-.004 1.304" />
+ <path android:fillColor="?attr/pointerIconVectorStroke" android:pathData="M10.55 5a4.546 4.546 0 1 0 0 9.093 4.546 4.546 0 0 0 0-9.093m2.462 5h-5a.5.5 0 0 1 0-1h5a.5.5 0 0 1 0 1" />
</group>
<group>
<path android:fillColor="?attr/pointerIconVectorFill" android:pathData="m19.736 18.003-4.194-4.22a6.547 6.547 0 1 0-1.382 1.226l4.268 4.294a.923.923 0 0 0 1.308-1.3m-9.186-3.91A4.546 4.546 0 1 1 10.549 5a4.546 4.546 0 0 1 .001 9.093" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index ea993ee1a208..4892f59bd9fb 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -10042,6 +10042,8 @@
<declare-styleable name="PointerIconVectorTheme">
<attr name="pointerIconVectorFill" format="color" />
<attr name="pointerIconVectorFillInverse" format="color" />
+ <attr name="pointerIconVectorStroke" format="color" />
+ <attr name="pointerIconVectorStrokeInverse" format="color" />
</declare-styleable>
<declare-styleable name="Storage">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 335b74025da3..ca80e2277ced 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4136,6 +4136,9 @@
<!-- The default value for keyboard vibration toggle in settings. -->
<bool name="config_defaultKeyboardVibrationEnabled">true</bool>
+ <!-- Indicating if keyboard vibration settings supported or not. -->
+ <bool name="config_keyboardVibrationSettingsSupported">false</bool>
+
<!-- If the device should still vibrate even in low power mode, for certain priority vibrations
(e.g. accessibility, alarms). This is mainly for Wear devices that don't have speakers. -->
<bool name="config_allowPriorityVibrationsInLowPowerMode">false</bool>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 61c7a8cde7d5..cdd8557393b8 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -393,6 +393,12 @@
<bool name="config_wait_for_device_alignment_in_demo_datagram">false</bool>
<java-symbol type="bool" name="config_wait_for_device_alignment_in_demo_datagram" />
+ <!-- Boolean indicating whether to enable MMS to be attempted on IWLAN if possible, even if
+ existing cellular networks already supports IWLAN.
+ -->
+ <bool name="force_iwlan_mms_feature_enabled">false</bool>
+ <java-symbol type="bool" name="force_iwlan_mms_feature_enabled" />
+
<!-- The time duration in millis after which Telephony will abort the last message datagram
sending requests. Telephony starts a timer when receiving a last message datagram sending
request in either OFF, IDLE, or NOT_CONNECTED state. In NOT_CONNECTED, the duration of the
diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml
index bd93aa9402c3..77d2e873682f 100644
--- a/core/res/res/values/locale_config.xml
+++ b/core/res/res/values/locale_config.xml
@@ -14,6 +14,11 @@
limitations under the License.
-->
+<!--
+ ICU Version: 75.1
+ CLDR Data Version: 45
+-->
+
<resources>
<string-array translatable="false" name="supported_locales">
@@ -88,6 +93,11 @@
<item>bem-ZM</item> <!-- Bemba (Zambia) -->
<item>bez-TZ</item> <!-- Bena (Tanzania) -->
<item>bg-BG</item> <!-- Bulgarian (Bulgaria) -->
+ <item>bgc-IN</item> <!-- Haryanvi (India) -->
+ <item>bgc-IN-u-nu-latn</item> <!-- Haryanvi (India, Western Digits) -->
+ <item>bho-IN</item> <!-- Bhojpuri (India) -->
+ <item>bho-IN-u-nu-latn</item> <!-- Bhojpuri (India, Western Digits) -->
+ <item>blo-BJ</item> <!-- Anii (Benin) -->
<item>bm-ML</item> <!-- Bambara (Mali) -->
<item>bn-BD</item> <!-- Bangla (Bangladesh) -->
<item>bn-BD-u-nu-latn</item> <!-- Bangla (Bangladesh, Western Digits) -->
@@ -108,6 +118,7 @@
<item>cgg-UG</item> <!-- Chiga (Uganda) -->
<item>chr-US</item> <!-- Cherokee (United States) -->
<item>cs-CZ</item> <!-- Czech (Czechia) -->
+ <item>csw-CA</item> <!-- Swampy Cree (Canada) -->
<item>cv-RU</item> <!-- Chuvash (Russia) -->
<item>cy-GB</item> <!-- Welsh (United Kingdom) -->
<item>da-DK</item> <!-- Danish (Denmark) -->
@@ -170,6 +181,7 @@
<item>en-GU</item> <!-- English (Guam) -->
<item>en-GY</item> <!-- English (Guyana) -->
<item>en-HK</item> <!-- English (Hong Kong) -->
+ <item>en-ID</item> <!-- English (Indonesia) -->
<item>en-IE</item> <!-- English (Ireland) -->
<item>en-IL</item> <!-- English (Israel) -->
<item>en-IM</item> <!-- English (Isle of Man) -->
@@ -237,6 +249,7 @@
<item>en-ZA</item> <!-- English (South Africa) -->
<item>en-ZM</item> <!-- English (Zambia) -->
<item>en-ZW</item> <!-- English (Zimbabwe) -->
+ <item>eo-001</item> <!-- Esperanto (world) -->
<item>es-AR</item> <!-- Spanish (Argentina) -->
<item>es-BO</item> <!-- Spanish (Bolivia) -->
<item>es-BR</item> <!-- Spanish (Brazil) -->
@@ -381,6 +394,7 @@
<item>hu-HU</item> <!-- Hungarian (Hungary) -->
<item>hy-AM</item> <!-- Armenian (Armenia) -->
<item>ia-001</item> <!-- Interlingua (world) -->
+ <item>ie-EE</item> <!-- Interlingue (Estonia) -->
<item>ig-NG</item> <!-- Igbo (Nigeria) -->
<item>ii-CN</item> <!-- Sichuan Yi (China) -->
<item>in-ID</item> <!-- Indonesian (Indonesia) -->
@@ -408,6 +422,7 @@
<item>kln-KE</item> <!-- Kalenjin (Kenya) -->
<item>km-KH</item> <!-- Khmer (Cambodia) -->
<item>kn-IN</item> <!-- Kannada (India) -->
+ <item>ko-CN</item> <!-- Korean (China) -->
<item>ko-KP</item> <!-- Korean (North Korea) -->
<item>ko-KR</item> <!-- Korean (South Korea) -->
<item>kok-IN</item> <!-- Konkani (India) -->
@@ -417,12 +432,19 @@
<item>ksb-TZ</item> <!-- Shambala (Tanzania) -->
<item>ksf-CM</item> <!-- Bafia (Cameroon) -->
<item>ksh-DE</item> <!-- Colognian (Germany) -->
+ <item>ku-TR</item> <!-- Kurdish (Türkiye) -->
<item>kw-GB</item> <!-- Cornish (United Kingdom) -->
+ <item>kxv-Deva-IN</item> <!-- Kuvi (Devanagari, India) -->
+ <item>kxv-Latn-IN</item> <!-- Kuvi (Latin, India) -->
+ <item>kxv-Orya-IN</item> <!-- Kuvi (Odia, India) -->
+ <item>kxv-Telu-IN</item> <!-- Kuvi (Telugu, India) -->
<item>ky-KG</item> <!-- Kyrgyz (Kyrgyzstan) -->
<item>lag-TZ</item> <!-- Langi (Tanzania) -->
<item>lb-LU</item> <!-- Luxembourgish (Luxembourg) -->
<item>lg-UG</item> <!-- Ganda (Uganda) -->
+ <item>lij-IT</item> <!-- Ligurian (Italy) -->
<item>lkt-US</item> <!-- Lakota (United States) -->
+ <item>lmo-IT</item> <!-- Lombard (Italy) -->
<item>ln-AO</item> <!-- Lingala (Angola) -->
<item>ln-CD</item> <!-- Lingala (Congo - Kinshasa) -->
<item>ln-CF</item> <!-- Lingala (Central African Republic) -->
@@ -462,6 +484,8 @@
<item>nb-NO</item> <!-- Norwegian Bokmål (Norway) -->
<item>nb-SJ</item> <!-- Norwegian Bokmål (Svalbard & Jan Mayen) -->
<item>nd-ZW</item> <!-- North Ndebele (Zimbabwe) -->
+ <item>nds-DE</item> <!-- Low German (Germany) -->
+ <item>nds-NL</item> <!-- Low German (Netherlands) -->
<item>ne-IN</item> <!-- Nepali (India) -->
<item>ne-IN-u-nu-latn</item> <!-- Nepali (India, Western Digits) -->
<item>ne-NP</item> <!-- Nepali (Nepal) -->
@@ -475,8 +499,12 @@
<item>nl-SX</item> <!-- Dutch (Sint Maarten) -->
<item>nn-NO</item> <!-- Norwegian Nynorsk (Norway) -->
<item>nnh-CM</item> <!-- Ngiemboon (Cameroon) -->
+ <item>nqo-GN</item> <!-- N’Ko (Guinea) -->
+ <item>nqo-GN-u-nu-latn</item> <!-- N’Ko (Guinea, Western Digits) -->
<item>nus-SS</item> <!-- Nuer (South Sudan) -->
<item>nyn-UG</item> <!-- Nyankole (Uganda) -->
+ <item>oc-ES</item> <!-- Occitan (Spain) -->
+ <item>oc-FR</item> <!-- Occitan (France) -->
<item>om-ET</item> <!-- Oromo (Ethiopia) -->
<item>om-KE</item> <!-- Oromo (Kenya) -->
<item>or-IN</item> <!-- Odia (India) -->
@@ -487,6 +515,7 @@
<item>pa-Guru-IN</item> <!-- Punjabi (Gurmukhi, India) -->
<item>pcm-NG</item> <!-- Nigerian Pidgin (Nigeria) -->
<item>pl-PL</item> <!-- Polish (Poland) -->
+ <item>prg-PL</item> <!-- Prussian (Poland) -->
<item>ps-AF</item> <!-- Pashto (Afghanistan) -->
<item>ps-AF-u-nu-latn</item> <!-- Pashto (Afghanistan, Western Digits) -->
<item>ps-PK</item> <!-- Pashto (Pakistan) -->
@@ -566,6 +595,9 @@
<item>sw-KE</item> <!-- Swahili (Kenya) -->
<item>sw-TZ</item> <!-- Swahili (Tanzania) -->
<item>sw-UG</item> <!-- Swahili (Uganda) -->
+ <item>syr-IQ</item> <!-- Syriac (Iraq) -->
+ <item>syr-SY</item> <!-- Syriac (Syria) -->
+ <item>szl-PL</item> <!-- Silesian (Poland) -->
<item>ta-IN</item> <!-- Tamil (India) -->
<item>ta-LK</item> <!-- Tamil (Sri Lanka) -->
<item>ta-MY</item> <!-- Tamil (Malaysia) -->
@@ -580,7 +612,7 @@
<item>tk-TM</item> <!-- Turkmen (Turkmenistan) -->
<item>to-TO</item> <!-- Tongan (Tonga) -->
<item>tr-CY</item> <!-- Turkish (Cyprus) -->
- <item>tr-TR</item> <!-- Turkish (Turkey) -->
+ <item>tr-TR</item> <!-- Turkish (Türkiye) -->
<item>tt-RU</item> <!-- Tatar (Russia) -->
<item>twq-NE</item> <!-- Tasawaq (Niger) -->
<item>tzm-MA</item> <!-- Central Atlas Tamazight (Morocco) -->
@@ -594,11 +626,14 @@
<item>uz-Arab-AF-u-nu-latn</item> <!-- Uzbek (Arabic, Afghanistan, Western Digits) -->
<item>uz-Cyrl-UZ</item> <!-- Uzbek (Cyrillic, Uzbekistan) -->
<item>uz-Latn-UZ</item> <!-- Uzbek (Latin, Uzbekistan) -->
+ <item>vec-IT</item> <!-- Venetian (Italy) -->
<item>vi-VN</item> <!-- Vietnamese (Vietnam) -->
+ <item>vmw-MZ</item> <!-- Makhuwa (Mozambique) -->
<item>vun-TZ</item> <!-- Vunjo (Tanzania) -->
<item>wae-CH</item> <!-- Walser (Switzerland) -->
<item>wo-SN</item> <!-- Wolof (Senegal) -->
<item>xh-ZA</item> <!-- Xhosa (South Africa) -->
+ <item>xnr-IN</item> <!-- Kangri (India) -->
<item>xog-UG</item> <!-- Soga (Uganda) -->
<item>yav-CM</item> <!-- Yangben (Cameroon) -->
<item>yo-BJ</item> <!-- Yoruba (Benin) -->
@@ -608,6 +643,7 @@
<item>yrl-VE</item> <!-- Nheengatu (Venezuela) -->
<item>yue-Hans-CN</item> <!-- Cantonese (Simplified, China) -->
<item>yue-Hant-HK</item> <!-- Cantonese (Traditional, Hong Kong) -->
+ <item>za-CN</item> <!-- Zhuang (China) -->
<item>zgh-MA</item> <!-- Standard Moroccan Tamazight (Morocco) -->
<item>zh-Hans-CN</item> <!-- Chinese (Simplified, China) -->
<item>zh-Hans-HK</item> <!-- Chinese (Simplified, Hong Kong) -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 50c3b1a93d75..aabc8ca5aef6 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1527,6 +1527,24 @@ please see styles_device_defaults.xml.
</style>
<!-- @hide -->
+ <style name="PointerIconVectorStyleStrokeWhite">
+ <item name="pointerIconVectorStroke">@color/white</item>
+ <item name="pointerIconVectorStrokeInverse">@color/black</item>
+ </style>
+
+ <!-- @hide -->
+ <style name="PointerIconVectorStyleStrokeBlack">
+ <item name="pointerIconVectorStroke">@color/black</item>
+ <item name="pointerIconVectorStrokeInverse">@color/white</item>
+ </style>
+
+ <!-- @hide -->
+ <style name="PointerIconVectorStyleStrokeNone">
+ <item name="pointerIconVectorStroke">@color/transparent</item>
+ <item name="pointerIconVectorStrokeInverse">@color/transparent</item>
+ </style>
+
+ <!-- @hide -->
<style name="aerr_list_item" parent="Widget.Material.Light.Button.Borderless">
<item name="minHeight">?attr/listPreferredItemHeightSmall</item>
<item name="textAppearance">?attr/textAppearanceListItemSmall</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7d50d227ee13..9661b4638718 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1704,6 +1704,10 @@
<java-symbol type="style" name="PointerIconVectorStyleFillPink" />
<java-symbol type="style" name="PointerIconVectorStyleFillBlue" />
<java-symbol type="attr" name="pointerIconVectorFill" />
+ <java-symbol type="style" name="PointerIconVectorStyleStrokeWhite" />
+ <java-symbol type="style" name="PointerIconVectorStyleStrokeBlack" />
+ <java-symbol type="style" name="PointerIconVectorStyleStrokeNone" />
+ <java-symbol type="attr" name="pointerIconVectorStroke" />
<java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Title" />
<java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Info" />
@@ -2122,6 +2126,7 @@
<java-symbol type="dimen" name="config_hapticChannelMaxVibrationAmplitude" />
<java-symbol type="dimen" name="config_keyboardHapticFeedbackFixedAmplitude" />
<java-symbol type="bool" name="config_defaultKeyboardVibrationEnabled" />
+ <java-symbol type="bool" name="config_keyboardVibrationSettingsSupported" />
<java-symbol type="integer" name="config_vibrationWaveformRampStepDuration" />
<java-symbol type="bool" name="config_ignoreVibrationsOnWirelessCharger" />
<java-symbol type="integer" name="config_vibrationWaveformRampDownDuration" />
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index 612b38762d2d..9ea2943bc6da 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -50,6 +50,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -393,19 +394,31 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
if (splitAttributes == null) {
return TaskFragmentAnimationParams.DEFAULT;
}
+ final TaskFragmentAnimationParams.Builder builder =
+ new TaskFragmentAnimationParams.Builder();
final int animationBackgroundColor = getAnimationBackgroundColor(splitAttributes);
- TaskFragmentAnimationParams.Builder builder = new TaskFragmentAnimationParams.Builder();
- if (animationBackgroundColor != DEFAULT_ANIMATION_BACKGROUND_COLOR) {
- builder.setAnimationBackgroundColor(animationBackgroundColor);
+ builder.setAnimationBackgroundColor(animationBackgroundColor);
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ final int openAnimationResId =
+ splitAttributes.getAnimationParams().getOpenAnimationResId();
+ builder.setOpenAnimationResId(openAnimationResId);
+ final int closeAnimationResId =
+ splitAttributes.getAnimationParams().getCloseAnimationResId();
+ builder.setCloseAnimationResId(closeAnimationResId);
+ final int changeAnimationResId =
+ splitAttributes.getAnimationParams().getChangeAnimationResId();
+ builder.setChangeAnimationResId(changeAnimationResId);
}
- // TODO(b/293658614): Allow setting custom open/close/changeAnimationResId.
return builder.build();
}
@ColorInt
private static int getAnimationBackgroundColor(@NonNull SplitAttributes splitAttributes) {
int animationBackgroundColor = DEFAULT_ANIMATION_BACKGROUND_COLOR;
- final AnimationBackground animationBackground = splitAttributes.getAnimationBackground();
+ AnimationBackground animationBackground = splitAttributes.getAnimationBackground();
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ animationBackground = splitAttributes.getAnimationParams().getAnimationBackground();
+ }
if (animationBackground instanceof AnimationBackground.ColorBackground colorBackground) {
animationBackgroundColor = colorBackground.getColor();
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
index 4267749dfa6b..c5aaddc4e0ed 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
@@ -29,6 +29,7 @@ import android.view.WindowManager;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.window.extensions.embedding.AnimationBackground;
+import androidx.window.extensions.embedding.AnimationParams;
import androidx.window.extensions.embedding.SplitAttributes;
import org.junit.Before;
@@ -112,5 +113,13 @@ public class WindowExtensionsTest {
.isEqualTo(new SplitAttributes.SplitType.RatioSplitType(0.5f));
assertThat(splitAttributes.getAnimationBackground())
.isEqualTo(AnimationBackground.ANIMATION_BACKGROUND_DEFAULT);
+ assertThat(splitAttributes.getAnimationParams().getAnimationBackground())
+ .isEqualTo(AnimationBackground.ANIMATION_BACKGROUND_DEFAULT);
+ assertThat(splitAttributes.getAnimationParams().getOpenAnimationResId())
+ .isEqualTo(AnimationParams.DEFAULT_ANIMATION_RESOURCES_ID);
+ assertThat(splitAttributes.getAnimationParams().getCloseAnimationResId())
+ .isEqualTo(AnimationParams.DEFAULT_ANIMATION_RESOURCES_ID);
+ assertThat(splitAttributes.getAnimationParams().getChangeAnimationResId())
+ .isEqualTo(AnimationParams.DEFAULT_ANIMATION_RESOURCES_ID);
}
}
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp b/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
index c6dbd9b25e7f..1871203c7600 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
@@ -22,6 +22,40 @@ package {
default_team: "trendy_team_multitasking_windowing",
}
+android_app {
+ name: "WMShellRobolectricScreenshotTestApp",
+ platform_apis: true,
+ certificate: "platform",
+ static_libs: [
+ "WindowManager-Shell",
+ "platform-screenshot-diff-core",
+ ],
+ asset_dirs: ["goldens/robolectric"],
+ manifest: "AndroidManifestRobolectric.xml",
+ use_resource_processor: true,
+}
+
+android_robolectric_test {
+ name: "WMShellRobolectricScreenshotTests",
+ instrumentation_for: "WMShellRobolectricScreenshotTestApp",
+ upstream: true,
+ java_resource_dirs: [
+ "robolectric/config",
+ ],
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "junit",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "truth",
+ "platform-parametric-runner-lib",
+ ],
+ auto_gen_config: true,
+}
+
android_test {
name: "WMShellMultivalentScreenshotTestsOnDevice",
srcs: [
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/AndroidManifestRobolectric.xml b/libs/WindowManager/Shell/multivalentScreenshotTests/AndroidManifestRobolectric.xml
index a7a3f1313a9b..b4bdaeaf0eac 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/AndroidManifestRobolectric.xml
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/AndroidManifestRobolectric.xml
@@ -16,7 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.wm.shell.multivalentscreenshot">
<application android:debuggable="true" android:supportsRtl="true">
- <uses-library android:name="android.test.runner" />
<activity
android:name="platform.test.screenshot.ScreenshotActivity"
android:exported="true">
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.png
new file mode 100644
index 000000000000..723c6b8d9c93
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.png
new file mode 100644
index 000000000000..723c6b8d9c93
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/robolectric/config/robolectric.properties b/libs/WindowManager/Shell/multivalentScreenshotTests/robolectric/config/robolectric.properties
index 7a0527ccaafb..d50d976c9e84 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/robolectric/config/robolectric.properties
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/robolectric/config/robolectric.properties
@@ -1,2 +1,3 @@
sdk=NEWEST_SDK
+graphicsMode=NATIVE
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
index dfc9c82d85ff..8f7fdd6a7b84 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
@@ -37,15 +37,12 @@ enum class DesktopModeFlags(
// All desktop mode related flags will be added here
DESKTOP_WINDOWING_MODE(DesktopModeStatus::isDesktopModeFlagEnabled, true);
- private val TAG = "DesktopModeFlags"
-
- // Cache for toggle override, which is initialized once on its first access. It needs to be refreshed
- // only on reboots as overridden state takes effect on reboots.
+ // Local cache for toggle override, which is initialized once on its first access. It needs to be
+ // refreshed only on reboots as overridden state takes effect on reboots.
private var cachedToggleOverride: ToggleOverride? = null
/**
- * Determines state of flag based on the actual flag and desktop mode developer option
- * overrides.
+ * Determines state of flag based on the actual flag and desktop mode developer option overrides.
*
* Note, this method makes sure that a constant developer toggle overrides is read until reboot.
*/
@@ -63,34 +60,44 @@ enum class DesktopModeFlags(
}
private fun getToggleOverride(context: Context): ToggleOverride {
- val override = cachedToggleOverride ?: run {
- // Cache toggle override the first time we encounter context. Override does not change
- // with context, as context is just used to fetch a system property.
+ val override =
+ cachedToggleOverride
+ ?: run {
+ val override = getToggleOverrideFromSystem(context)
+ // Cache toggle override the first time we encounter context. Override does not change
+ // with context, as context is just used to fetch System Property and Settings.Global
+ cachedToggleOverride = override
+ Log.d(TAG, "Toggle override initialized to: $override")
+ override
+ }
- // TODO(b/348193756): Cache a persistent value for Settings.Global until reboot. Current
- // cache will change with process restart.
- val toggleOverride =
- Settings.Global.getInt(
- context.contentResolver,
- Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
- ToggleOverride.OVERRIDE_UNSET.setting)
+ return override
+ }
- val newOverride =
- settingToToggleOverrideMap[toggleOverride]
- ?: run {
- Log.w(TAG, "Unknown toggleOverride $toggleOverride")
- ToggleOverride.OVERRIDE_UNSET
- }
- cachedToggleOverride = newOverride
- Log.d(TAG, "Toggle override initialized to: $newOverride")
- newOverride
- }
+ private fun getToggleOverrideFromSystem(context: Context): ToggleOverride {
+ // A non-persistent System Property is used to store override to ensure it remains
+ // constant till reboot.
+ val overrideFromSystemProperties: ToggleOverride? =
+ System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null).convertToToggleOverride()
+ return overrideFromSystemProperties
+ ?: run {
+ // Read Setting Global if System Property is not present (just after reboot)
+ // or not valid (user manually changed the value)
+ val overrideFromSettingsGlobal =
+ Settings.Global.getInt(
+ context.contentResolver,
+ Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
+ ToggleOverride.OVERRIDE_UNSET.setting)
+ .convertToToggleOverrideWithFallback(ToggleOverride.OVERRIDE_UNSET)
+ // Initialize System Property
+ System.setProperty(
+ SYSTEM_PROPERTY_OVERRIDE_KEY, overrideFromSettingsGlobal.setting.toString())
- return override
+ overrideFromSettingsGlobal
+ }
}
- // TODO(b/348193756): Share ToggleOverride enum with Settings
- // 'DesktopModePreferenceController'
+ // TODO(b/348193756): Share ToggleOverride enum with Settings 'DesktopModePreferenceController'
/**
* Override state of desktop mode developer option toggle.
*
@@ -107,4 +114,33 @@ enum class DesktopModeFlags(
}
private val settingToToggleOverrideMap = ToggleOverride.entries.associateBy { it.setting }
+
+ private fun String?.convertToToggleOverride(): ToggleOverride? {
+ val intValue = this?.toIntOrNull() ?: return null
+ return settingToToggleOverrideMap[intValue]
+ ?: run {
+ Log.w(TAG, "Unknown toggleOverride int $intValue")
+ null
+ }
+ }
+
+ private fun Int.convertToToggleOverrideWithFallback(
+ fallbackOverride: ToggleOverride
+ ): ToggleOverride {
+ return settingToToggleOverrideMap[this]
+ ?: run {
+ Log.w(TAG, "Unknown toggleOverride int $this")
+ fallbackOverride
+ }
+ }
+
+ private companion object {
+ const val TAG = "DesktopModeFlags"
+
+ /**
+ * Key for non-persistent System Property which is used to store desktop windowing developer
+ * option overrides.
+ */
+ const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override"
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index d270d2b4ccf1..5696a544152c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -266,6 +266,9 @@ class ActivityEmbeddingAnimationRunner {
final Animation animation =
animationProvider.get(info, change, openingWholeScreenBounds);
if (shouldUseJumpCutForAnimation(animation)) {
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ return new ArrayList<>();
+ }
continue;
}
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
@@ -291,6 +294,9 @@ class ActivityEmbeddingAnimationRunner {
final Animation animation =
animationProvider.get(info, change, closingWholeScreenBounds);
if (shouldUseJumpCutForAnimation(animation)) {
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ return new ArrayList<>();
+ }
continue;
}
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index f49b90d08a75..3046307702c2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -97,7 +97,7 @@ class ActivityEmbeddingAnimationSpec {
Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) {
if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
- final Animation customAnimation = loadCustomAnimation(info, change);
+ final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE);
if (customAnimation != null) {
return customAnimation;
}
@@ -131,7 +131,7 @@ class ActivityEmbeddingAnimationSpec {
Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) {
if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
- final Animation customAnimation = loadCustomAnimation(info, change);
+ final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE);
if (customAnimation != null) {
return customAnimation;
}
@@ -172,7 +172,7 @@ class ActivityEmbeddingAnimationSpec {
// TODO(b/293658614): Support more complicated animations that may need more than a noop
// animation as the start leash.
final Animation noopAnimation = createNoopAnimation(change);
- final Animation customAnimation = loadCustomAnimation(info, change);
+ final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE);
if (customAnimation != null) {
return new Animation[]{noopAnimation, customAnimation};
}
@@ -227,7 +227,7 @@ class ActivityEmbeddingAnimationSpec {
Animation loadOpenAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
final boolean isEnter = TransitionUtil.isOpeningType(change.getMode());
- final Animation customAnimation = loadCustomAnimation(info, change);
+ final Animation customAnimation = loadCustomAnimation(info, change, change.getMode());
final Animation animation;
if (customAnimation != null) {
animation = customAnimation;
@@ -254,7 +254,7 @@ class ActivityEmbeddingAnimationSpec {
Animation loadCloseAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
final boolean isEnter = TransitionUtil.isOpeningType(change.getMode());
- final Animation customAnimation = loadCustomAnimation(info, change);
+ final Animation customAnimation = loadCustomAnimation(info, change, change.getMode());
final Animation animation;
if (customAnimation != null) {
animation = customAnimation;
@@ -287,14 +287,14 @@ class ActivityEmbeddingAnimationSpec {
@Nullable
private Animation loadCustomAnimation(@NonNull TransitionInfo info,
- @NonNull TransitionInfo.Change change) {
+ @NonNull TransitionInfo.Change change, @WindowManager.TransitionType int mode) {
final TransitionInfo.AnimationOptions options;
if (Flags.moveAnimationOptionsToChange()) {
options = change.getAnimationOptions();
} else {
options = info.getAnimationOptions();
}
- return loadCustomAnimationFromOptions(options, change.getMode());
+ return loadCustomAnimationFromOptions(options, mode);
}
@Nullable
@@ -319,8 +319,14 @@ class ActivityEmbeddingAnimationSpec {
return null;
}
- final Animation anim = mTransitionAnimation.loadAnimationRes(options.getPackageName(),
- resId);
+ final Animation anim;
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ // TODO(b/293658614): Consider allowing custom animations from non-default packages.
+ // Enforce limiting to animations from the default "android" package for now.
+ anim = mTransitionAnimation.loadDefaultAnimationRes(resId);
+ } else {
+ anim = mTransitionAnimation.loadAnimationRes(options.getPackageName(), resId);
+ }
if (anim != null) {
return anim;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt
index 6781d08c9904..d1b2347a4411 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt
@@ -19,6 +19,16 @@
package com.android.wm.shell.compatui
import android.app.TaskInfo
-fun isSingleTopActivityTranslucent(task: TaskInfo) =
- task.isTopActivityTransparent && task.numActivities == 1
+import android.content.Context
+import com.android.internal.R
+// TODO(b/347289970): Consider replacing with API
+fun isTopActivityExemptFromDesktopWindowing(context: Context, task: TaskInfo) =
+ isSystemUiTask(context, task) || (task.isTopActivityTransparent && task.numActivities == 1
+ && !task.isTopActivityStyleFloating)
+
+private fun isSystemUiTask(context: Context, task: TaskInfo): Boolean {
+ val sysUiPackageName: String =
+ context.resources.getString(R.string.config_systemUi)
+ return task.baseActivity?.packageName == sysUiPackageName
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index da1d6daff8c6..e792f7ad4263 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -24,7 +24,6 @@ import android.os.Handler;
import android.os.UserManager;
import android.view.Choreographer;
import android.view.IWindowManager;
-import android.view.SurfaceControl;
import android.view.WindowManager;
import com.android.internal.jank.InteractionJankMonitor;
@@ -404,8 +403,7 @@ public abstract class WMShellModule {
Optional<RecentTasksController> recentTasksController,
HomeTransitionObserver homeTransitionObserver) {
return new RecentsTransitionHandler(shellInit, transitions,
- recentTasksController.orElse(null), homeTransitionObserver,
- SurfaceControl.Transaction::new);
+ recentTasksController.orElse(null), homeTransitionObserver);
}
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 4868a2f2f905..e24791292085 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -66,7 +66,7 @@ import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
-import com.android.wm.shell.compatui.isSingleTopActivityTranslucent
+import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener
import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener
import com.android.wm.shell.draganddrop.DragAndDropController
@@ -158,8 +158,6 @@ class DesktopTasksController(
visualIndicator = null
}
}
- private val sysUIPackageName = context.resources.getString(
- com.android.internal.R.string.config_systemUi)
private val transitionAreaHeight
get() =
@@ -219,11 +217,6 @@ class DesktopTasksController(
return visualIndicator
}
- // TODO(b/347289970): Consider replacing with API
- private fun isSystemUIApplication(taskInfo: RunningTaskInfo): Boolean {
- return taskInfo.baseActivity?.packageName == sysUIPackageName
- }
-
fun setOnTaskResizeAnimationListener(listener: OnTaskResizeAnimationListener) {
toggleResizeDesktopTaskTransitionHandler.setOnTaskResizeAnimationListener(listener)
enterDesktopTaskTransitionHandler.setOnTaskResizeAnimationListener(listener)
@@ -351,19 +344,12 @@ class DesktopTasksController(
wct: WindowContainerTransaction = WindowContainerTransaction(),
transitionSource: DesktopModeTransitionSource,
) {
- if (Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)) {
- KtProtoLog.w(
- WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: Cannot enter desktop, " +
- "translucent top activity found. This is likely a modal dialog."
- )
- return
- }
- if (isSystemUIApplication(task)) {
+ if (Flags.enableDesktopWindowingModalsPolicy()
+ && isTopActivityExemptFromDesktopWindowing(context, task)) {
KtProtoLog.w(
WM_SHELL_DESKTOP_MODE,
"DesktopTasksController: Cannot enter desktop, " +
- "systemUI top activity found."
+ "ineligible top activity found."
)
return
}
@@ -942,10 +928,8 @@ class DesktopTasksController(
when {
// Check if the closing task needs to be handled
TransitionUtil.isClosingType(request.type) -> handleTaskClosing(task)
- // Check if the task has a top transparent activity
- shouldLaunchAsModal(task) -> handleIncompatibleTaskLaunch(task)
- // Check if the task has a top systemUI activity
- isSystemUIApplication(task) -> handleIncompatibleTaskLaunch(task)
+ // Check if the top task shouldn't be allowed to enter desktop mode
+ isIncompatibleTask(task) -> handleIncompatibleTaskLaunch(task)
// Check if fullscreen task should be updated
task.isFullscreen -> handleFullscreenTaskLaunch(task, transition)
// Check if freeform task should be updated
@@ -979,9 +963,9 @@ class DesktopTasksController(
.forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) }
}
- // TODO(b/347289970): Consider replacing with API
- private fun shouldLaunchAsModal(task: TaskInfo) =
- Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)
+ private fun isIncompatibleTask(task: TaskInfo) =
+ Flags.enableDesktopWindowingModalsPolicy()
+ && isTopActivityExemptFromDesktopWindowing(context, task)
private fun shouldHandleTaskClosing(request: TransitionRequestInfo): Boolean {
return Flags.enableDesktopWindowingWallpaperActivity() &&
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index e46625debcc6..234b4d0f86db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -74,7 +74,6 @@ import com.android.wm.shell.transition.Transitions;
import java.util.ArrayList;
import java.util.function.Consumer;
-import java.util.function.Supplier;
/**
* Handles the Recents (overview) animation. Only one of these can run at a time. A recents
@@ -85,7 +84,6 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
private final Transitions mTransitions;
private final ShellExecutor mExecutor;
- private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
@Nullable
private final RecentTasksController mRecentTasksController;
private IApplicationThread mAnimApp = null;
@@ -103,13 +101,11 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
public RecentsTransitionHandler(ShellInit shellInit, Transitions transitions,
@Nullable RecentTasksController recentTasksController,
- HomeTransitionObserver homeTransitionObserver,
- Supplier<SurfaceControl.Transaction> transactionSupplier) {
+ HomeTransitionObserver homeTransitionObserver) {
mTransitions = transitions;
mExecutor = transitions.getMainExecutor();
mRecentTasksController = recentTasksController;
mHomeTransitionObserver = homeTransitionObserver;
- mTransactionSupplier = transactionSupplier;
if (!Transitions.ENABLE_SHELL_TRANSITIONS) return;
if (recentTasksController == null) return;
shellInit.addInitCallback(() -> {
@@ -1060,7 +1056,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
final Transitions.TransitionFinishCallback finishCB = mFinishCB;
mFinishCB = null;
- SurfaceControl.Transaction t = mFinishTransaction;
+ final SurfaceControl.Transaction t = mFinishTransaction;
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (mKeyguardLocked && mRecentsTask != null) {
@@ -1110,16 +1106,6 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
}
}
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, " normal finish");
- if (toHome && !mOpeningTasks.isEmpty()) {
- // Attempting to start a task after swipe to home, don't show it,
- // move recents to top
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- " attempting to start a task after swipe to home");
- t = mTransactionSupplier.get();
- wct.reorder(mRecentsTask, true /*onTop*/);
- mClosingTasks.addAll(mOpeningTasks);
- mOpeningTasks.clear();
- }
// The general case: committing to recents, going home, or switching tasks.
for (int i = 0; i < mOpeningTasks.size(); ++i) {
t.show(mOpeningTasks.get(i).mTaskSurface);
@@ -1188,10 +1174,6 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
mPipTransaction = null;
}
}
- if (t != mFinishTransaction) {
- // apply after merges because these changes are accounting for finishWCT changes.
- mTransitions.setAfterMergeFinishTransaction(mTransition, t);
- }
cleanUp();
finishCB.onTransitionFinished(wct.isEmpty() ? null : wct);
if (runnerFinishCb != null) {
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 b8abf8f2a3c0..21307a2edae0 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
@@ -77,6 +77,7 @@ import androidx.annotation.BinderThread;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
+import com.android.window.flags.Flags;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
@@ -242,13 +243,6 @@ public class Transitions implements RemoteCallable<Transitions>,
/** Ordered list of transitions which have been merged into this one. */
private ArrayList<ActiveTransition> mMerged;
- /**
- * @deprecated DO NOT USE THIS unless absolutely necessary. It will be removed once
- * everything migrates off finishWCT.
- */
- @java.lang.Deprecated
- SurfaceControl.Transaction mAfterMergeFinishT;
-
ActiveTransition(IBinder token) {
mToken = token;
}
@@ -586,6 +580,14 @@ public class Transitions implements RemoteCallable<Transitions>,
final boolean isOpening = isOpeningType(transitType);
final boolean isClosing = isClosingType(transitType);
final int mode = change.getMode();
+ // Ensure wallpapers stay in the back
+ if (change.hasFlags(FLAG_IS_WALLPAPER) && Flags.ensureWallpaperInTransitions()) {
+ if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
+ return -zSplitLine + numChanges - i;
+ } else {
+ return -zSplitLine - i;
+ }
+ }
// Put all the OPEN/SHOW on top
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
if (isOpening) {
@@ -1034,20 +1036,6 @@ public class Transitions implements RemoteCallable<Transitions>,
return null;
}
- /** @deprecated */
- @java.lang.Deprecated
- public void setAfterMergeFinishTransaction(IBinder transition,
- SurfaceControl.Transaction afterMergeFinishT) {
- final ActiveTransition at = mKnownTransitions.get(transition);
- if (at == null) return;
- if (at.mAfterMergeFinishT != null) {
- Log.e(TAG, "Setting after-merge-t >1 time on transition: " + at.mInfo.getDebugId());
- at.mAfterMergeFinishT.merge(afterMergeFinishT);
- return;
- }
- at.mAfterMergeFinishT = afterMergeFinishT;
- }
-
/** Aborts a transition. This will still queue it up to maintain order. */
private void onAbort(ActiveTransition transition) {
final Track track = mTracks.get(transition.getTrack());
@@ -1108,7 +1096,6 @@ public class Transitions implements RemoteCallable<Transitions>,
}
// Merge all associated transactions together
SurfaceControl.Transaction fullFinish = active.mFinishT;
- SurfaceControl.Transaction afterMergeFinish = active.mAfterMergeFinishT;
if (active.mMerged != null) {
for (int iM = 0; iM < active.mMerged.size(); ++iM) {
final ActiveTransition toMerge = active.mMerged.get(iM);
@@ -1128,21 +1115,6 @@ public class Transitions implements RemoteCallable<Transitions>,
fullFinish.merge(toMerge.mFinishT);
}
}
- if (toMerge.mAfterMergeFinishT != null) {
- if (afterMergeFinish == null) {
- afterMergeFinish = toMerge.mAfterMergeFinishT;
- } else {
- afterMergeFinish.merge(toMerge.mAfterMergeFinishT);
- }
- toMerge.mAfterMergeFinishT = null;
- }
- }
- }
- if (afterMergeFinish != null) {
- if (fullFinish == null) {
- fullFinish = afterMergeFinish;
- } else {
- fullFinish.merge(afterMergeFinish);
}
}
if (fullFinish != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index e3aa31f7e286..440fc4d314bb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -32,7 +32,7 @@ import static android.view.WindowInsets.Type.statusBars;
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.compatui.AppCompatUtils.isSingleTopActivityTranslucent;
+import static com.android.wm.shell.compatui.AppCompatUtils.isTopActivityExemptFromDesktopWindowing;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -105,7 +105,6 @@ import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
import java.io.PrintWriter;
-import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
@@ -1034,12 +1033,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
&& taskInfo.isFocused) {
return false;
}
- // TODO(b/347289970): Consider replacing with API
if (Flags.enableDesktopWindowingModalsPolicy()
- && isSingleTopActivityTranslucent(taskInfo)) {
- return false;
- }
- if (isSystemUIApplication(taskInfo)) {
+ && isTopActivityExemptFromDesktopWindowing(mContext, taskInfo)) {
return false;
}
return DesktopModeStatus.canEnterDesktopMode(mContext)
@@ -1118,14 +1113,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
&& mSplitScreenController.isTaskInSplitScreen(taskId);
}
- // TODO(b/347289970): Consider replacing with API
- private boolean isSystemUIApplication(RunningTaskInfo taskInfo) {
- if (taskInfo.baseActivity != null) {
- return (Objects.equals(taskInfo.baseActivity.getPackageName(), mSysUIPackageName));
- }
- return false;
- }
-
private void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + "DesktopModeWindowDecorViewModel");
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index a0a61fe2cf72..d0e8215e662e 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -117,12 +117,10 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli
/**
* Checks that all parts of the screen are covered at the start and end of the transition
- *
- * TODO b/197726599 Prevents all states from being checked
*/
@Presubmit
@Test
- fun entireScreenCoveredAtStartAndEnd() = flicker.entireScreenCovered(allStates = false)
+ fun entireScreenCoveredAtStartAndEnd() = flicker.entireScreenCovered()
/** Checks [pipApp] window remains visible and on top throughout the transition */
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
index 4cd2a366f5eb..ecaf970ae389 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
@@ -16,8 +16,10 @@
package com.android.wm.shell.compatui
+import android.content.ComponentName
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
+import com.android.internal.R
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
import org.junit.Assert.assertFalse
@@ -34,26 +36,55 @@ import org.junit.runner.RunWith
@RunWith(AndroidTestingRunner::class)
@SmallTest
class AppCompatUtilsTest : ShellTestCase() {
-
@Test
- fun testIsSingleTopActivityTranslucent() {
- assertTrue(isSingleTopActivityTranslucent(
+ fun testIsTopActivityExemptFromDesktopWindowing_topActivityTransparent() {
+ assertTrue(isTopActivityExemptFromDesktopWindowing(mContext,
createFreeformTask(/* displayId */ 0)
.apply {
isTopActivityTransparent = true
numActivities = 1
}))
- assertFalse(isSingleTopActivityTranslucent(
+ assertFalse(isTopActivityExemptFromDesktopWindowing(mContext,
createFreeformTask(/* displayId */ 0)
.apply {
isTopActivityTransparent = true
numActivities = 0
}))
- assertFalse(isSingleTopActivityTranslucent(
+ }
+
+ @Test
+ fun testIsTopActivityExemptFromDesktopWindowing_singleTopActivity() {
+ assertTrue(isTopActivityExemptFromDesktopWindowing(mContext,
+ createFreeformTask(/* displayId */ 0)
+ .apply {
+ isTopActivityTransparent = true
+ numActivities = 1
+ }))
+ assertFalse(isTopActivityExemptFromDesktopWindowing(mContext,
createFreeformTask(/* displayId */ 0)
.apply {
isTopActivityTransparent = false
numActivities = 1
}))
}
-} \ No newline at end of file
+
+ @Test
+ fun testIsTopActivityExemptFromDesktopWindowing__topActivityStyleFloating() {
+ assertFalse(isTopActivityExemptFromDesktopWindowing(mContext,
+ createFreeformTask(/* displayId */ 0)
+ .apply {
+ isTopActivityStyleFloating = true
+ }))
+ }
+
+ @Test
+ fun testIsTopActivityExemptFromDesktopWindowing_systemUiTask() {
+ val systemUIPackageName = context.resources.getString(R.string.config_systemUi)
+ val baseComponent = ComponentName(systemUIPackageName, /* class */ "")
+ assertTrue(isTopActivityExemptFromDesktopWindowing(mContext,
+ createFreeformTask(/* displayId */ 0)
+ .apply {
+ baseActivity = baseComponent
+ }))
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 8c7de5c24bb8..bd38d360a15b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -700,19 +700,37 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
- fun moveToDesktop_topActivityTranslucent_doesNothing() {
- setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ fun moveToDesktop_topActivityTranslucentWithStyleFloating_taskIsMovedToDesktop() {
val task =
- setUpFullscreenTask().apply {
- isTopActivityTransparent = true
- numActivities = 1
- }
+ setUpFullscreenTask().apply {
+ isTopActivityTransparent = true
+ isTopActivityStyleFloating = true
+ numActivities = 1
+ }
+
+ controller.moveToDesktop(task, transitionSource = UNKNOWN)
+
+ val wct = getLatestEnterDesktopWct()
+ assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ fun moveToDesktop_topActivityTranslucentWithoutStyleFloating_doesNothing() {
+ val task =
+ setUpFullscreenTask().apply {
+ isTopActivityTransparent = true
+ isTopActivityStyleFloating = false
+ numActivities = 1
+ }
controller.moveToDesktop(task, transitionSource = UNKNOWN)
verifyEnterDesktopWCTNotExecuted()
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
fun moveToDesktop_systemUIActivity_doesNothing() {
val task = setUpFullscreenTask()
@@ -1374,20 +1392,40 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
- fun handleRequest_shouldLaunchAsModal_returnSwitchToFullscreenWCT() {
- setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ fun handleRequest_topActivityTransparentWithStyleFloating_returnSwitchToFreeformWCT() {
+ val freeformTask = setUpFreeformTask()
+ markTaskVisible(freeformTask)
+
val task =
- setUpFreeformTask().apply {
- isTopActivityTransparent = true
- numActivities = 1
- }
+ setUpFullscreenTask().apply {
+ isTopActivityTransparent = true
+ isTopActivityStyleFloating = true
+ numActivities = 1
+ }
val result = controller.handleRequest(Binder(), createTransition(task))
assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode)
- .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+ .isEqualTo(WINDOWING_MODE_FREEFORM)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ fun handleRequest_topActivityTransparentWithoutStyleFloating_returnSwitchToFullscreenWCT() {
+ val task =
+ setUpFreeformTask().apply {
+ isTopActivityTransparent = true
+ isTopActivityStyleFloating = false
+ numActivities = 1
+ }
+
+ val result = controller.handleRequest(Binder(), createTransition(task))
+ assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
fun handleRequest_systemUIActivity_returnSwitchToFullscreenWCT() {
val task = setUpFreeformTask()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
index 115b218f2e82..17983b27f4e8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
@@ -82,7 +82,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_unsetOverride_featureFlagOn_returnsTrue() {
+ fun isEnabled_overrideUnset_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_UNSET.setting)
// For overridableFlag, for unset overrides, follow flag
@@ -92,7 +92,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_unsetOverride_featureFlagOff_returnsFalse() {
+ fun isEnabled_overrideUnset_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_UNSET.setting)
// For overridableFlag, for unset overrides, follow flag
@@ -101,7 +101,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_noOverride_featureFlagOn_returnsTrue() {
+ fun isEnabled_noOverride_featureFlagOn_returnsTrue() {
setOverride(null)
// For overridableFlag, in absence of overrides, follow flag
@@ -111,7 +111,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_noOverride_featureFlagOff_returnsFalse() {
+ fun isEnabled_noOverride_featureFlagOff_returnsFalse() {
setOverride(null)
// For overridableFlag, in absence of overrides, follow flag
@@ -120,7 +120,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_unrecognizableOverride_featureFlagOn_returnsTrue() {
+ fun isEnabled_unrecognizableOverride_featureFlagOn_returnsTrue() {
setOverride(-2)
// For overridableFlag, for recognizable overrides, follow flag
@@ -130,7 +130,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_unrecognizableOverride_featureFlagOff_returnsFalse() {
+ fun isEnabled_unrecognizableOverride_featureFlagOff_returnsFalse() {
setOverride(-2)
// For overridableFlag, for recognizable overrides, follow flag
@@ -139,7 +139,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_overrideOff_featureFlagOn_returnsFalse() {
+ fun isEnabled_overrideOff_featureFlagOn_returnsFalse() {
setOverride(OVERRIDE_OFF.setting)
// For overridableFlag, follow override if they exist
@@ -149,7 +149,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_overrideOn_featureFlagOff_returnsTrue() {
+ fun isEnabled_overrideOn_featureFlagOff_returnsTrue() {
setOverride(OVERRIDE_ON.setting)
// For overridableFlag, follow override if they exist
@@ -158,7 +158,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() {
+ fun isEnabled_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() {
setOverride(OVERRIDE_OFF.setting)
// For overridableFlag, follow override if they exist
@@ -173,7 +173,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() {
+ fun isEnabled_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() {
setOverride(OVERRIDE_ON.setting)
// For overridableFlag, follow override if they exist
@@ -187,7 +187,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_noOverride_featureFlagOnThenOff_returnsTrueAndFalse() {
+ fun isEnabled_noOverride_featureFlagOnThenOff_returnsTrueAndFalse() {
setOverride(null)
// For overridableFlag, in absence of overrides, follow flag
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
@@ -206,6 +206,108 @@ class DesktopModeFlagsTest : ShellTestCase() {
}
}
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ fun isEnabled_noSystemProperty_overrideOn_featureFlagOff_returnsTrueAndStoresPropertyOn() {
+ System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
+ setOverride(OVERRIDE_ON.setting)
+
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
+ // Store System Property if not present
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_ON.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ fun isEnabled_noSystemProperty_overrideUnset_featureFlagOn_returnsTrueAndStoresPropertyUnset() {
+ System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
+ setOverride(OVERRIDE_UNSET.setting)
+
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
+ // Store System Property if not present
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_UNSET.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ fun isEnabled_noSystemProperty_overrideUnset_featureFlagOff_returnsFalseAndStoresPropertyUnset() {
+ System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
+ setOverride(OVERRIDE_UNSET.setting)
+
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
+ // Store System Property if not present
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_UNSET.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ @Suppress("ktlint:standard:max-line-length")
+ fun isEnabled_systemPropertyNotInteger_overrideOff_featureFlagOn_returnsFalseAndStoresPropertyOff() {
+ System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "abc")
+ setOverride(OVERRIDE_OFF.setting)
+
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
+ // Store System Property if currently invalid
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_OFF.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ @Suppress("ktlint:standard:max-line-length")
+ fun isEnabled_systemPropertyInvalidInteger_overrideOff_featureFlagOn_returnsFalseAndStoresPropertyOff() {
+ System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "-2")
+ setOverride(OVERRIDE_OFF.setting)
+
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
+ // Store System Property if currently invalid
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_OFF.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ fun isEnabled_systemPropertyOff_overrideOn_featureFlagOn_returnsFalseAndDoesNotUpdateProperty() {
+ System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_OFF.setting.toString())
+ setOverride(OVERRIDE_ON.setting)
+
+ // Have a consistent override until reboot
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_OFF.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ fun isEnabled_systemPropertyOn_overrideOff_featureFlagOff_returnsTrueAndDoesNotUpdateProperty() {
+ System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_ON.setting.toString())
+ setOverride(OVERRIDE_OFF.setting)
+
+ // Have a consistent override until reboot
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_ON.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ @Suppress("ktlint:standard:max-line-length")
+ fun isEnabled_systemPropertyUnset_overrideOff_featureFlagOn_returnsTrueAndDoesNotUpdateProperty() {
+ System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_UNSET.setting.toString())
+ setOverride(OVERRIDE_OFF.setting)
+
+ // Have a consistent override until reboot
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_UNSET.setting.toString())
+ }
+
private fun setOverride(setting: Int?) {
val contentResolver = mContext.contentResolver
val key = Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES
@@ -217,9 +319,16 @@ class DesktopModeFlagsTest : ShellTestCase() {
}
private fun resetCache() {
- val cacheToggleOverride =
+ val cachedToggleOverride =
DESKTOP_WINDOWING_MODE::class.java.getDeclaredField("cachedToggleOverride")
- cacheToggleOverride.isAccessible = true
- cacheToggleOverride.set(DESKTOP_WINDOWING_MODE, null)
+ cachedToggleOverride.isAccessible = true
+ cachedToggleOverride.set(DESKTOP_WINDOWING_MODE, null)
+
+ // Clear override cache stored in System property
+ System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
+ }
+
+ private companion object {
+ const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override"
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 8331d591fd59..409b87723e79 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -1191,8 +1191,7 @@ public class ShellTransitionTests extends ShellTestCase {
mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class));
final RecentsTransitionHandler recentsHandler =
new RecentsTransitionHandler(shellInit, transitions,
- mock(RecentTasksController.class), mock(HomeTransitionObserver.class),
- () -> mock(SurfaceControl.Transaction.class));
+ mock(RecentTasksController.class), mock(HomeTransitionObserver.class));
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
shellInit.init();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index 0ec671314cdf..0bf5a674aabb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -348,10 +348,35 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
}
@Test
- fun testDecorationIsNotCreatedForTopTranslucentActivities() {
- setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ fun testDecorationIsCreatedForTopTranslucentActivitiesWithStyleFloating() {
+ val mockitoSession: StaticMockitoSession = mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .spyStatic(DesktopModeStatus::class.java)
+ .startMocking()
+ try {
+ val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply {
+ isTopActivityTransparent = true
+ isTopActivityStyleFloating = true
+ numActivities = 1
+ }
+ doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+ setUpMockDecorationsForTasks(task)
+
+ onTaskOpening(task)
+ verify(mockDesktopModeWindowDecorFactory)
+ .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+ } finally {
+ mockitoSession.finishMocking()
+ }
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ fun testDecorationIsNotCreatedForTopTranslucentActivitiesWithoutStyleFloating() {
val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply {
isTopActivityTransparent = true
+ isTopActivityStyleFloating = false
numActivities = 1
}
onTaskOpening(task)
@@ -361,6 +386,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
fun testDecorationIsNotCreatedForSystemUIActivities() {
val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true)
diff --git a/packages/SettingsLib/ActionButtonsPreference/Android.bp b/packages/SettingsLib/ActionButtonsPreference/Android.bp
index c36b82d175e2..71ecb4c30543 100644
--- a/packages/SettingsLib/ActionButtonsPreference/Android.bp
+++ b/packages/SettingsLib/ActionButtonsPreference/Android.bp
@@ -19,7 +19,6 @@ android_library {
static_libs: [
"androidx.preference_preference",
- "SettingsLibUtils",
],
sdk_version: "system_current",
diff --git a/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java b/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
index 3e65d94e3323..5dc11cfc0392 100644
--- a/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
+++ b/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
@@ -31,12 +32,11 @@ import androidx.annotation.StringRes;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
-import com.android.settingslib.utils.BuildCompatUtils;
+import com.android.settingslib.widget.preference.actionbuttons.R;
+
import java.util.ArrayList;
import java.util.List;
-import com.android.settingslib.widget.preference.actionbuttons.R;
-
/**
* This preference provides a four buttons layout with Settings style.
* It looks like below
@@ -56,7 +56,7 @@ import com.android.settingslib.widget.preference.actionbuttons.R;
public class ActionButtonsPreference extends Preference {
private static final String TAG = "ActionButtonPreference";
- private static final boolean mIsAtLeastS = BuildCompatUtils.isAtLeastS();
+ private static final boolean mIsAtLeastS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
private static final int SINGLE_BUTTON_STYLE = 1;
private static final int TWO_BUTTONS_STYLE = 2;
private static final int THREE_BUTTONS_STYLE = 3;
diff --git a/packages/SettingsLib/ActivityEmbedding/Android.bp b/packages/SettingsLib/ActivityEmbedding/Android.bp
index 838a9e505ece..556100212445 100644
--- a/packages/SettingsLib/ActivityEmbedding/Android.bp
+++ b/packages/SettingsLib/ActivityEmbedding/Android.bp
@@ -20,7 +20,6 @@ android_library {
"androidx.annotation_annotation",
"androidx.core_core",
"androidx.window_window",
- "SettingsLibUtils",
],
sdk_version: "system_current",
min_sdk_version: "21",
diff --git a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
index f89be9fba583..67aa8f41e227 100644
--- a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
+++ b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
@@ -20,13 +20,11 @@ import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.util.Log;
-import androidx.core.os.BuildCompat;
import androidx.window.embedding.ActivityEmbeddingController;
-import com.android.settingslib.utils.BuildCompatUtils;
-
/**
* An util class collecting all common methods for the embedding activity features.
*/
@@ -70,7 +68,7 @@ public final class ActivityEmbeddingUtils {
* enabled (unsupported devices).
*/
private static ComponentName getEmbeddingActivityComponent(Context context) {
- if (!BuildCompatUtils.isAtLeastSV2()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S_V2) {
return null;
}
final Intent intent = new Intent(ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY);
@@ -95,7 +93,7 @@ public final class ActivityEmbeddingUtils {
* Settings app
*/
public static boolean shouldHideNavigateUpButton(Activity activity, boolean isSecondLayerPage) {
- if (!BuildCompat.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
return false;
}
diff --git a/packages/SettingsLib/BannerMessagePreference/Android.bp b/packages/SettingsLib/BannerMessagePreference/Android.bp
index 07290de8661e..3f671b9e7b10 100644
--- a/packages/SettingsLib/BannerMessagePreference/Android.bp
+++ b/packages/SettingsLib/BannerMessagePreference/Android.bp
@@ -20,7 +20,6 @@ android_library {
static_libs: [
"androidx.preference_preference",
"SettingsLibSettingsTheme",
- "SettingsLibUtils",
],
sdk_version: "system_current",
diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
index 33775a64aa82..6cd777e878fe 100644
--- a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
+++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
@@ -38,7 +38,6 @@ import androidx.annotation.StringRes;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
-import com.android.settingslib.utils.BuildCompatUtils;
import com.android.settingslib.widget.preference.banner.R;
/**
* Banner message is a banner displaying important information (permission request, page error etc),
@@ -84,7 +83,7 @@ public class BannerMessagePreference extends Preference {
}
private static final String TAG = "BannerPreference";
- private static final boolean IS_AT_LEAST_S = BuildCompatUtils.isAtLeastS();
+ private static final boolean IS_AT_LEAST_S = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
private final BannerMessagePreference.ButtonInfo mPositiveButtonInfo =
new BannerMessagePreference.ButtonInfo();
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index 87ec0b8d46fb..483403971864 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -22,7 +22,6 @@ android_library {
"androidx.core_core",
"com.google.android.material_material",
"SettingsLibSettingsTransition",
- "SettingsLibUtils",
"SettingsLibSettingsTheme",
],
sdk_version: "system_current",
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java
index 8ebbac39d1d0..b252e5f021ae 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java
@@ -16,11 +16,11 @@
package com.android.settingslib.collapsingtoolbar;
+import android.os.Build;
+
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceFragmentCompat;
-import com.android.settingslib.utils.BuildCompatUtils;
-
import com.google.android.material.appbar.AppBarLayout;
/**
@@ -58,7 +58,7 @@ public abstract class BasePreferencesFragment extends PreferenceFragmentCompat {
if (activity != null) {
activity.setTitle(getTitle());
- if (BuildCompatUtils.isAtLeastS()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
AppBarLayout appBarLayout = (AppBarLayout) activity.findViewById(R.id.app_bar);
if (appBarLayout != null) {
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarAppCompatActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarAppCompatActivity.java
index 04c44e6d11be..8b27626a08e4 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarAppCompatActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarAppCompatActivity.java
@@ -17,6 +17,7 @@
package com.android.settingslib.collapsingtoolbar;
import android.app.ActionBar;
+import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -26,8 +27,6 @@ import android.widget.Toolbar;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
-import com.android.settingslib.utils.BuildCompatUtils;
-
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.color.DynamicColors;
@@ -66,12 +65,12 @@ public class CollapsingToolbarAppCompatActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (BuildCompatUtils.isAtLeastS()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
DynamicColors.applyToActivityIfAvailable(this);
}
setTheme(com.android.settingslib.widget.theme.R.style.Theme_SubSettingsBase);
- if (mCustomizeLayoutResId > 0 && !BuildCompatUtils.isAtLeastS()) {
+ if (mCustomizeLayoutResId > 0 && Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
super.setContentView(mCustomizeLayoutResId);
return;
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index 143101f76977..86ce2ab6109f 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -18,6 +18,7 @@ package com.android.settingslib.collapsingtoolbar;
import android.app.ActionBar;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -27,8 +28,6 @@ import android.widget.Toolbar;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
-import com.android.settingslib.utils.BuildCompatUtils;
-
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
@@ -60,7 +59,8 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// for backward compatibility on R devices or wearable devices due to small device size.
- if (mCustomizeLayoutResId > 0 && (!BuildCompatUtils.isAtLeastS() || isWatch())) {
+ if (mCustomizeLayoutResId > 0 && (Build.VERSION.SDK_INT < Build.VERSION_CODES.S
+ || isWatch())) {
super.setContentView(mCustomizeLayoutResId);
return;
}
diff --git a/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
index c52386bef07b..7be448207efe 100644
--- a/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
+++ b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
@@ -30,7 +30,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import androidx.core.os.BuildCompat;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
@@ -226,7 +225,8 @@ public abstract class ProfileSelectFragment extends Fragment {
// to be here only for this API level - when then private profile was introduced.
@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
private boolean shouldShowPrivateProfileIfItsOne(UserHandle userHandle) {
- if (!BuildCompat.isAtLeastV() || !android.os.Flags.allowPrivateProfile()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM
+ || !android.os.Flags.allowPrivateProfile()) {
return false;
}
try {
diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
deleted file mode 100644
index bf3651b2cdad..000000000000
--- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.utils;
-
-import android.os.Build;
-
-import androidx.annotation.ChecksSdkIntAtLeast;
-
-/**
- * An util class to check whether the current OS version is higher or equal to sdk version of
- * device.
- */
-public final class BuildCompatUtils {
-
- /**
- * Implementation of BuildCompat.isAtLeastS() suitable for use in Settings
- *
- * @return Whether the current OS version is higher or equal to S.
- */
- @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
- public static boolean isAtLeastS() {
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
- }
-
- /**
- * Implementation of BuildCompat.isAtLeastS() suitable for use in Settings
- *
- * @return Whether the current OS version is higher or equal to Sv2.
- */
- @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S_V2)
- public static boolean isAtLeastSV2() {
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2;
- }
-
- /**
- * Implementation of BuildCompat.isAtLeastT() suitable for use in Settings
- *
- * @return Whether the current OS version is higher or equal to T.
- */
- @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
- public static boolean isAtLeastT() {
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
- }
-
- private BuildCompatUtils() {}
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 734b92c7ac6e..6ca9279de8c6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -38,8 +38,6 @@ import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
-import com.android.settingslib.utils.BuildCompatUtils;
-
/**
* Helper class for managing settings preferences that can be disabled
* by device admins via user restrictions.
@@ -120,9 +118,10 @@ public class RestrictedPreferenceHelper {
if (mDisabledSummary) {
final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
if (summaryView != null) {
- final CharSequence disabledText = BuildCompatUtils.isAtLeastT()
- ? getDisabledByAdminUpdatableString()
- : mContext.getString(R.string.disabled_by_admin_summary_text);
+ final CharSequence disabledText =
+ (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
+ ? getDisabledByAdminUpdatableString()
+ : mContext.getString(R.string.disabled_by_admin_summary_text);
if (mDisabledByAdmin) {
summaryView.setText(disabledText);
} else if (mDisabledByEcm) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 45754eb8f16d..fffbb547c662 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -25,6 +25,7 @@ import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
import android.util.AttributeSet;
@@ -40,8 +41,6 @@ import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.SwitchPreferenceCompat;
-import com.android.settingslib.utils.BuildCompatUtils;
-
/**
* Version of SwitchPreferenceCompat that can be disabled by a device admin
* using a user restriction.
@@ -164,7 +163,7 @@ public class RestrictedSwitchPreference extends SwitchPreferenceCompat {
private static String getUpdatableEnterpriseString(
Context context, String updatableStringId, int resId) {
- if (!BuildCompatUtils.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
return context.getString(resId);
}
return context.getSystemService(DevicePolicyManager.class).getResources().getString(
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index c2506d353d14..b02b0c454644 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -66,7 +66,6 @@ import com.android.launcher3.util.UserIconInfo;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.settingslib.fuelgauge.BatteryUtils;
-import com.android.settingslib.utils.BuildCompatUtils;
import java.util.List;
@@ -147,7 +146,7 @@ public class Utils {
String name = info != null ? info.name : null;
if (info.isManagedProfile()) {
// We use predefined values for managed profiles
- return BuildCompatUtils.isAtLeastT()
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
? getUpdatableManagedUserTitle(context)
: context.getString(R.string.managed_user_title);
} else if (info.isGuest()) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 721e7b93fd32..53441c08776f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -24,6 +24,7 @@ import android.media.AudioManager;
import android.net.Uri;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -808,7 +809,8 @@ public class BluetoothUtils {
* <p>If CachedBluetoothDevice#getGroupId is invalid, fetch group id from
* LeAudioProfile#getGroupId.
*/
- public static int getGroupId(@NonNull CachedBluetoothDevice cachedDevice) {
+ public static int getGroupId(@Nullable CachedBluetoothDevice cachedDevice) {
+ if (cachedDevice == null) return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
int groupId = cachedDevice.getGroupId();
String anonymizedAddress = cachedDevice.getDevice().getAnonymizedAddress();
if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
@@ -824,4 +826,44 @@ public class BluetoothUtils {
Log.d(TAG, "getGroupId return invalid id for device: " + anonymizedAddress);
return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
}
+
+ /** Get primary device Uri in broadcast. */
+ @NonNull
+ public static String getPrimaryGroupIdUriForBroadcast() {
+ return "bluetooth_le_broadcast_fallback_active_group_id";
+ }
+
+ /** Get primary device group id in broadcast. */
+ @WorkerThread
+ public static int getPrimaryGroupIdForBroadcast(@NonNull Context context) {
+ return Settings.Secure.getInt(
+ context.getContentResolver(),
+ getPrimaryGroupIdUriForBroadcast(),
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ }
+
+ /** Get secondary {@link CachedBluetoothDevice} in broadcast. */
+ @Nullable
+ @WorkerThread
+ public static CachedBluetoothDevice getSecondaryDeviceForBroadcast(
+ @NonNull Context context, @Nullable LocalBluetoothManager localBtManager) {
+ if (localBtManager == null) return null;
+ int primaryGroupId = getPrimaryGroupIdForBroadcast(context);
+ if (primaryGroupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) return null;
+ LocalBluetoothLeBroadcastAssistant assistant =
+ localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+ CachedBluetoothDeviceManager deviceManager = localBtManager.getCachedDeviceManager();
+ List<BluetoothDevice> devices = assistant.getAllConnectedDevices();
+ for (BluetoothDevice device : devices) {
+ CachedBluetoothDevice cachedDevice = deviceManager.findDevice(device);
+ if (hasConnectedBroadcastSource(cachedDevice, localBtManager)) {
+ int groupId = getGroupId(cachedDevice);
+ if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
+ && groupId != primaryGroupId) {
+ return cachedDevice;
+ }
+ }
+ }
+ return null;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
index ea65adecd763..84afb9f7a7e2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
@@ -25,7 +25,6 @@ import android.util.Log;
import androidx.annotation.EmptySuper;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
-import androidx.core.os.BuildCompat;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
@@ -141,7 +140,7 @@ public abstract class AbstractPreferenceController {
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
protected void replaceEnterpriseStringTitle(PreferenceScreen screen,
String preferenceKey, String overrideKey, int resource) {
- if (!BuildCompat.isAtLeastT() || mDevicePolicyManager == null) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || mDevicePolicyManager == null) {
return;
}
@@ -159,7 +158,7 @@ public abstract class AbstractPreferenceController {
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
protected void replaceEnterpriseStringSummary(
PreferenceScreen screen, String preferenceKey, String overrideKey, int resource) {
- if (!BuildCompat.isAtLeastT() || mDevicePolicyManager == null) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || mDevicePolicyManager == null) {
return;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index f07daa3add8b..243403e018b6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -48,8 +48,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
-import com.android.settingslib.utils.BuildCompatUtils;
-
/**
* Converts the user avatar icon to a circularly clipped one with an optional badge and frame
*/
@@ -88,7 +86,7 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback {
* @return drawable containing just the badge
*/
public static Drawable getManagedUserDrawable(Context context) {
- if (BuildCompatUtils.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
return getUpdatableManagedUserDrawable(context);
} else {
return getDrawableForDisplayDensity(
@@ -227,7 +225,7 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback {
}
private static Drawable getManagementBadge(Context context) {
- if (BuildCompatUtils.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
return getUpdatableManagementBadge(context);
} else {
return getDrawableForDisplayDensity(
diff --git a/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/ZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/ZenModeRepository.kt
index 4d25237757ea..29527646b89f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/ZenModeRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/ZenModeRepository.kt
@@ -73,12 +73,12 @@ class ZenModeRepositoryImpl(
awaitClose { context.unregisterReceiver(receiver) }
}
- .apply {
+ .let {
if (Flags.volumePanelBroadcastFix()) {
- flowOn(backgroundCoroutineContext)
- stateIn(scope, SharingStarted.WhileSubscribed(), null)
+ it.flowOn(backgroundCoroutineContext)
+ .stateIn(scope, SharingStarted.WhileSubscribed(), null)
} else {
- shareIn(
+ it.shareIn(
started = SharingStarted.WhileSubscribed(),
scope = scope,
)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index a638df524740..28bf34882365 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -22,11 +22,13 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.content.Context;
@@ -36,10 +38,13 @@ import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.Uri;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
import android.util.Pair;
import com.android.settingslib.widget.AdaptiveIcon;
+import com.google.common.collect.ImmutableList;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -562,4 +567,77 @@ public class BluetoothUtilsTest {
assertThat(BluetoothUtils.isAvailableHearingDevice(mCachedBluetoothDevice)).isEqualTo(true);
}
+
+ @Test
+ public void getGroupId_getCsipProfileId() {
+ when(mCachedBluetoothDevice.getGroupId()).thenReturn(1);
+
+ assertThat(BluetoothUtils.getGroupId(mCachedBluetoothDevice)).isEqualTo(1);
+ }
+
+ @Test
+ public void getGroupId_getLeAudioProfileId() {
+ when(mCachedBluetoothDevice.getGroupId())
+ .thenReturn(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+ LeAudioProfile leAudio = mock(LeAudioProfile.class);
+ when(leAudio.getGroupId(mBluetoothDevice)).thenReturn(1);
+ when(mCachedBluetoothDevice.getProfiles()).thenReturn(ImmutableList.of(leAudio));
+
+ assertThat(BluetoothUtils.getGroupId(mCachedBluetoothDevice)).isEqualTo(1);
+ }
+
+ @Test
+ public void getSecondaryDeviceForBroadcast_errorState_returnNull() {
+ assertThat(BluetoothUtils.getSecondaryDeviceForBroadcast(mContext, mLocalBluetoothManager))
+ .isNull();
+ }
+
+ @Test
+ public void getSecondaryDeviceForBroadcast_noSecondary_returnNull() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
+ 1);
+ CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+ when(deviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+ when(mCachedBluetoothDevice.getGroupId()).thenReturn(1);
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of(state));
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mBluetoothDevice));
+
+ assertThat(BluetoothUtils.getSecondaryDeviceForBroadcast(mContext, mLocalBluetoothManager))
+ .isNull();
+ }
+
+ @Test
+ public void getSecondaryDeviceForBroadcast_returnCorrectDevice() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
+ 1);
+ CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+ CachedBluetoothDevice cachedBluetoothDevice = mock(CachedBluetoothDevice.class);
+ BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
+ when(cachedBluetoothDevice.getDevice()).thenReturn(bluetoothDevice);
+ when(cachedBluetoothDevice.getGroupId()).thenReturn(1);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+ when(mCachedBluetoothDevice.getGroupId()).thenReturn(2);
+ when(deviceManager.findDevice(bluetoothDevice)).thenReturn(cachedBluetoothDevice);
+ when(deviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ List<Long> bisSyncState = new ArrayList<>();
+ bisSyncState.add(1L);
+ when(state.getBisSyncState()).thenReturn(bisSyncState);
+ when(mAssistant.getAllSources(any(BluetoothDevice.class)))
+ .thenReturn(ImmutableList.of(state));
+ when(mAssistant.getAllConnectedDevices())
+ .thenReturn(ImmutableList.of(mBluetoothDevice, bluetoothDevice));
+
+ assertThat(BluetoothUtils.getSecondaryDeviceForBroadcast(mContext, mLocalBluetoothManager))
+ .isEqualTo(mCachedBluetoothDevice);
+ }
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 00fb7a1feab1..2cdd0aee3d85 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -80,6 +80,7 @@ public class SystemSettings {
Settings.System.SIP_RECEIVE_CALLS,
Settings.System.POINTER_SPEED,
Settings.System.POINTER_FILL_STYLE,
+ Settings.System.POINTER_STROKE_STYLE,
Settings.System.POINTER_SCALE,
Settings.System.VIBRATE_ON,
Settings.System.VIBRATE_WHEN_RINGING,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 4235bc4157bf..7b927d793c37 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -30,6 +30,8 @@ import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
import static android.view.PointerIcon.LARGE_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BEGIN;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_END;
+import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_BEGIN;
+import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_END;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -213,6 +215,9 @@ public class SystemSettingsValidators {
VALIDATORS.put(System.POINTER_FILL_STYLE,
new InclusiveIntegerRangeValidator(POINTER_ICON_VECTOR_STYLE_FILL_BEGIN,
POINTER_ICON_VECTOR_STYLE_FILL_END));
+ VALIDATORS.put(System.POINTER_STROKE_STYLE,
+ new InclusiveIntegerRangeValidator(POINTER_ICON_VECTOR_STYLE_STROKE_BEGIN,
+ POINTER_ICON_VECTOR_STYLE_STROKE_END));
VALIDATORS.put(System.POINTER_SCALE,
new InclusiveFloatRangeValidator(DEFAULT_POINTER_SCALE, LARGE_POINTER_SCALE));
VALIDATORS.put(System.TOUCHPAD_POINTER_SPEED, new InclusiveIntegerRangeValidator(-7, 7));
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 384cb7ee9c49..cd37ad171fac 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2916,6 +2916,9 @@ class SettingsProtoDumpUtil {
Settings.System.POINTER_FILL_STYLE,
SystemSettingsProto.Pointer.POINTER_FILL_STYLE);
dumpSetting(s, p,
+ Settings.System.POINTER_STROKE_STYLE,
+ SystemSettingsProto.Pointer.POINTER_STROKE_STYLE);
+ dumpSetting(s, p,
Settings.System.POINTER_SCALE,
SystemSettingsProto.Pointer.POINTER_SCALE);
p.end(pointerToken);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index b5776e253485..469b9cef0411 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -23,7 +23,10 @@ package {
// See: http://go/android-license-faq
license {
name: "frameworks_base_packages_SystemUI_license",
- visibility: [":__subpackages__"],
+ visibility: [
+ ":__subpackages__",
+ "//development/samples/SceneTransitionLayoutDemo:__subpackages__",
+ ],
license_kinds: [
"SPDX-license-identifier-Apache-2.0",
],
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 18fbf7769426..07f74367fd06 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1052,13 +1052,6 @@ flag {
}
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"
-}
-
-flag {
name: "glanceable_hub_allow_keyguard_when_dreaming"
namespace: "systemui"
description: "Allows users to exit dream to keyguard with glanceable hub enabled"
@@ -1143,4 +1136,14 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
-} \ No newline at end of file
+}
+
+flag {
+ namespace: "systemui"
+ name: "fetch_bookmarks_xml_keyboard_shortcuts"
+ description: "Fetches application launch keyboard shortcuts from system server rather than building a hardcoded list."
+ bug: "312452252"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
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 bb76c1d668e3..cc4e7752ab21 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
@@ -9,21 +9,14 @@ import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
-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.draw.alpha
import androidx.compose.ui.draw.drawBehind
@@ -48,7 +41,6 @@ import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.transitions
import com.android.compose.theme.LocalAndroidColorScheme
-import com.android.systemui.Flags
import com.android.systemui.communal.shared.model.CommunalBackgroundType
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
@@ -156,8 +148,6 @@ fun CommunalContainer(
val currentSceneKey: SceneKey by
viewModel.currentScene.collectAsStateWithLifecycle(CommunalScenes.Blank)
val touchesAllowed by viewModel.touchesAllowed.collectAsStateWithLifecycle()
- val showGestureIndicator by
- viewModel.showGestureIndicator.collectAsStateWithLifecycle(initialValue = false)
val backgroundType by
viewModel.communalBackground.collectAsStateWithLifecycle(
initialValue = CommunalBackgroundType.ANIMATED
@@ -200,19 +190,7 @@ fun CommunalContainer(
)
) {
// This scene shows nothing only allowing for transitions to the communal scene.
- // 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))
- }
- }
+ Box(modifier = Modifier.fillMaxSize())
}
scene(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index be51c1a76fad..97ed74f0f07a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -119,6 +119,7 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.CustomAccessibilityAction
+import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.onClick
@@ -871,7 +872,7 @@ private fun CtaTileInViewModeContent(
Icon(
imageVector = Icons.Outlined.Widgets,
contentDescription = stringResource(R.string.cta_label_to_open_widget_picker),
- modifier = Modifier.size(Dimensions.IconSize),
+ modifier = Modifier.size(Dimensions.IconSize).clearAndSetSemantics {},
)
Spacer(modifier = Modifier.size(6.dp))
Text(
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index e8fdfc8da3bc..d95b388eb347 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -913,6 +913,7 @@ internal class NestedScrollHandlerImpl(
private val topOrLeftBehavior: NestedScrollBehavior,
private val bottomOrRightBehavior: NestedScrollBehavior,
private val isExternalOverscrollGesture: () -> Boolean,
+ private val pointersInfoOwner: PointersInfoOwner,
) {
private val layoutState = layoutImpl.state
private val draggableHandler = layoutImpl.draggableHandler(orientation)
@@ -924,25 +925,12 @@ internal class NestedScrollHandlerImpl(
// moving on to the next scene.
var canChangeScene = false
- val actionUpOrLeft =
- Swipe(
- direction =
- when (orientation) {
- Orientation.Horizontal -> SwipeDirection.Left
- Orientation.Vertical -> SwipeDirection.Up
- },
- pointerCount = 1,
- )
-
- val actionDownOrRight =
- Swipe(
- direction =
- when (orientation) {
- Orientation.Horizontal -> SwipeDirection.Right
- Orientation.Vertical -> SwipeDirection.Down
- },
- pointerCount = 1,
- )
+ var _lastPointersInfo: PointersInfo? = null
+ fun pointersInfo(): PointersInfo {
+ return checkNotNull(_lastPointersInfo) {
+ "PointersInfo should be initialized before the transition begins."
+ }
+ }
fun hasNextScene(amount: Float): Boolean {
val transitionState = layoutState.transitionState
@@ -950,8 +938,30 @@ internal class NestedScrollHandlerImpl(
val fromScene = layoutImpl.scene(scene)
val nextScene =
when {
- amount < 0f -> fromScene.userActions[actionUpOrLeft]
- amount > 0f -> fromScene.userActions[actionDownOrRight]
+ amount < 0f -> {
+ val actionUpOrLeft =
+ Swipe(
+ direction =
+ when (orientation) {
+ Orientation.Horizontal -> SwipeDirection.Left
+ Orientation.Vertical -> SwipeDirection.Up
+ },
+ pointerCount = pointersInfo().pointersDown,
+ )
+ fromScene.userActions[actionUpOrLeft]
+ }
+ amount > 0f -> {
+ val actionDownOrRight =
+ Swipe(
+ direction =
+ when (orientation) {
+ Orientation.Horizontal -> SwipeDirection.Right
+ Orientation.Vertical -> SwipeDirection.Down
+ },
+ pointerCount = pointersInfo().pointersDown,
+ )
+ fromScene.userActions[actionDownOrRight]
+ }
else -> null
}
if (nextScene != null) return true
@@ -985,6 +995,8 @@ internal class NestedScrollHandlerImpl(
return@PriorityNestedScrollConnection false
}
+ _lastPointersInfo = pointersInfoOwner.pointersInfo()
+
// If the current swipe transition is *not* closed to 0f or 1f, then we want the
// scroll events to intercept the current transition to continue the scene
// transition.
@@ -1002,6 +1014,8 @@ internal class NestedScrollHandlerImpl(
val isZeroOffset =
if (isExternalOverscrollGesture()) false else offsetBeforeStart == 0f
+ _lastPointersInfo = pointersInfoOwner.pointersInfo()
+
val canStart =
when (behavior) {
NestedScrollBehavior.DuringTransitionBetweenScenes -> {
@@ -1039,6 +1053,8 @@ internal class NestedScrollHandlerImpl(
// We could start an overscroll animation
canChangeScene = false
+ _lastPointersInfo = pointersInfoOwner.pointersInfo()
+
val canStart = behavior.canStartOnPostFling && hasNextScene(velocityAvailable)
if (canStart) {
isIntercepting = false
@@ -1049,10 +1065,11 @@ internal class NestedScrollHandlerImpl(
canContinueScroll = { true },
canScrollOnFling = false,
onStart = { offsetAvailable ->
+ val pointersInfo = pointersInfo()
dragController =
draggableHandler.onDragStarted(
- pointersDown = 1,
- startedPosition = null,
+ pointersDown = pointersInfo.pointersDown,
+ startedPosition = pointersInfo.startedPosition,
overSlop = if (isIntercepting) 0f else offsetAvailable,
)
},
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index f40f26578302..cdcfc84ce92a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -29,18 +29,21 @@ import androidx.compose.ui.input.pointer.PointerId
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.PointerInputScope
import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
-import androidx.compose.ui.input.pointer.changedToDownIgnoreConsumed
+import androidx.compose.ui.input.pointer.changedToDown
import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed
import androidx.compose.ui.input.pointer.positionChange
import androidx.compose.ui.input.pointer.positionChangeIgnoreConsumed
import androidx.compose.ui.input.pointer.util.VelocityTracker
import androidx.compose.ui.input.pointer.util.addPointerInputChange
import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
+import androidx.compose.ui.node.DelegatableNode
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.node.ObserverModifierNode
import androidx.compose.ui.node.PointerInputModifierNode
+import androidx.compose.ui.node.TraversableNode
import androidx.compose.ui.node.currentValueOf
+import androidx.compose.ui.node.findNearestAncestor
import androidx.compose.ui.node.observeReads
import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.unit.IntSize
@@ -48,11 +51,12 @@ import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.util.fastAll
import androidx.compose.ui.util.fastAny
import androidx.compose.ui.util.fastFirstOrNull
-import androidx.compose.ui.util.fastForEach
+import androidx.compose.ui.util.fastSumBy
import kotlin.coroutines.cancellation.CancellationException
import kotlin.math.sign
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
/**
* Make an element draggable in the given [orientation].
@@ -112,6 +116,18 @@ private data class MultiPointerDraggableElement(
}
}
+private val TRAVERSE_KEY = Any()
+
+/** Find the nearest [PointersInfoOwner] ancestor or throw. */
+internal fun DelegatableNode.requireAncestorPointersInfoOwner(): PointersInfoOwner {
+ val ancestorNode =
+ checkNotNull(findNearestAncestor(TRAVERSE_KEY)) {
+ "This should never happen! Couldn't find a MultiPointerDraggableNode. " +
+ "Are we inside an SceneTransitionLayout?"
+ }
+ return ancestorNode as PointersInfoOwner
+}
+
internal class MultiPointerDraggableNode(
orientation: Orientation,
enabled: () -> Boolean,
@@ -120,15 +136,19 @@ internal class MultiPointerDraggableNode(
(startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController,
var swipeDetector: SwipeDetector = DefaultSwipeDetector,
) :
- PointerInputModifierNode,
DelegatingNode(),
+ PointerInputModifierNode,
CompositionLocalConsumerModifierNode,
+ TraversableNode,
+ PointersInfoOwner,
ObserverModifierNode {
private val pointerInputHandler: suspend PointerInputScope.() -> Unit = { pointerInput() }
private val delegate = delegate(SuspendingPointerInputModifierNode(pointerInputHandler))
private val velocityTracker = VelocityTracker()
private var previousEnabled: Boolean = false
+ override val traverseKey: Any = TRAVERSE_KEY
+
var enabled: () -> Boolean = enabled
set(value) {
// Reset the pointer input whenever enabled changed.
@@ -185,12 +205,42 @@ internal class MultiPointerDraggableNode(
bounds: IntSize
) = delegate.onPointerEvent(pointerEvent, pass, bounds)
+ private var startedPosition: Offset? = null
+ private var pointersDown: Int = 0
+
+ override fun pointersInfo(): PointersInfo {
+ return PointersInfo(
+ startedPosition = startedPosition,
+ // Note: We could have 0 pointers during fling or for other reasons.
+ pointersDown = pointersDown.coerceAtLeast(1),
+ )
+ }
+
private suspend fun PointerInputScope.pointerInput() {
if (!enabled()) {
return
}
coroutineScope {
+ launch {
+ // Intercepts pointer inputs and exposes [PointersInfo], via
+ // [requireAncestorPointersInfoOwner], to our descendants.
+ awaitPointerEventScope {
+ while (isActive) {
+ // During the Initial pass, we receive the event after our ancestors.
+ val pointers = awaitPointerEvent(PointerEventPass.Initial).changes
+
+ pointersDown = pointers.countDown()
+ if (pointersDown == 0) {
+ // There are no more pointers down
+ startedPosition = null
+ } else if (startedPosition == null) {
+ startedPosition = pointers.first().position
+ }
+ }
+ }
+ }
+
awaitPointerEventScope {
while (isActive) {
try {
@@ -314,15 +364,16 @@ internal class MultiPointerDraggableNode(
}
if (drag != null) {
- // Count the number of pressed pointers.
- val pressed = mutableSetOf<PointerId>()
- currentEvent.changes.fastForEach { change ->
- if (change.pressed) {
- pressed.add(change.id)
- }
- }
-
- val controller = onDragStart(drag.position, overSlop, pressed.size)
+ val controller =
+ onDragStart(
+ // The startedPosition is the starting position when a gesture begins (when the
+ // first pointer touches the screen), not the point where we begin dragging.
+ // For example, this could be different if one of our children intercepts the
+ // gesture first and then we do.
+ requireNotNull(startedPosition),
+ overSlop,
+ pointersDown,
+ )
val successful: Boolean
try {
@@ -364,12 +415,10 @@ internal class MultiPointerDraggableNode(
fun canBeConsumed(changes: List<PointerInputChange>): Boolean {
// At least one pointer down AND
return changes.fastAny { it.pressed } &&
- // All pointers must be:
+ // All pointers must be either:
changes.fastAll {
- // A) recently pressed: even if the event has already been consumed, we can
- // still use the recently added finger event to determine whether to initiate
- // dragging the scene.
- it.changedToDownIgnoreConsumed() ||
+ // A) unconsumed AND recently pressed
+ it.changedToDown() ||
// B) unconsumed AND in a new position (on the current axis)
it.positionChange().toFloat() != 0f
}
@@ -461,4 +510,15 @@ internal class MultiPointerDraggableNode(
}
}
}
+
+ private fun List<PointerInputChange>.countDown() = fastSumBy { if (it.pressed) 1 else 0 }
}
+
+internal fun interface PointersInfoOwner {
+ fun pointersInfo(): PointersInfo
+}
+
+internal data class PointersInfo(
+ val startedPosition: Offset?,
+ val pointersDown: Int,
+)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index 1fa6b3f7d6c0..ddff2f709082 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -128,6 +128,7 @@ private class NestedScrollToSceneNode(
bottomOrRightBehavior: NestedScrollBehavior,
isExternalOverscrollGesture: () -> Boolean,
) : DelegatingNode() {
+ lateinit var pointersInfoOwner: PointersInfoOwner
private var priorityNestedScrollConnection: PriorityNestedScrollConnection =
scenePriorityNestedScrollConnection(
layoutImpl = layoutImpl,
@@ -135,6 +136,7 @@ private class NestedScrollToSceneNode(
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
+ pointersInfoOwner = { pointersInfoOwner.pointersInfo() }
)
private var nestedScrollNode: DelegatableNode =
@@ -144,6 +146,7 @@ private class NestedScrollToSceneNode(
)
override fun onAttach() {
+ pointersInfoOwner = requireAncestorPointersInfoOwner()
delegate(nestedScrollNode)
}
@@ -171,6 +174,7 @@ private class NestedScrollToSceneNode(
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
+ pointersInfoOwner = pointersInfoOwner,
)
nestedScrollNode =
nestedScrollModifierNode(
@@ -187,6 +191,7 @@ private fun scenePriorityNestedScrollConnection(
topOrLeftBehavior: NestedScrollBehavior,
bottomOrRightBehavior: NestedScrollBehavior,
isExternalOverscrollGesture: () -> Boolean,
+ pointersInfoOwner: PointersInfoOwner,
) =
NestedScrollHandlerImpl(
layoutImpl = layoutImpl,
@@ -194,5 +199,6 @@ private fun scenePriorityNestedScrollConnection(
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
+ pointersInfoOwner = pointersInfoOwner,
)
.connection
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 65b388f66a0d..ff83d4b93af8 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -113,7 +113,10 @@ class DraggableHandlerTest {
orientation = draggableHandler.orientation,
topOrLeftBehavior = nestedScrollBehavior,
bottomOrRightBehavior = nestedScrollBehavior,
- isExternalOverscrollGesture = { isExternalOverscrollGesture }
+ isExternalOverscrollGesture = { isExternalOverscrollGesture },
+ pointersInfoOwner = {
+ PointersInfo(startedPosition = Offset.Zero, pointersDown = 1)
+ }
)
.connection
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 2de6faaccca2..1ae999282afa 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -839,6 +839,80 @@ class ElementTest {
}
@Test
+ fun elementTransitionDuringNestedScrollWith2Pointers() {
+ // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
+ // detected as a drag event.
+ var touchSlop = 0f
+ val translateY = 10.dp
+ val layoutWidth = 200.dp
+ val layoutHeight = 400.dp
+
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ initialScene = SceneA,
+ transitions =
+ transitions {
+ from(SceneA, to = SceneB) {
+ translate(TestElements.Foo, y = translateY)
+ }
+ },
+ )
+ as MutableSceneTransitionLayoutStateImpl
+ }
+
+ rule.setContent {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ SceneTransitionLayout(
+ state = state,
+ modifier = Modifier.size(layoutWidth, layoutHeight)
+ ) {
+ scene(
+ SceneA,
+ userActions = mapOf(Swipe(SwipeDirection.Down, pointerCount = 2) to SceneB)
+ ) {
+ Box(
+ Modifier
+ // Unconsumed scroll gesture will be intercepted by STL
+ .verticalNestedScrollToScene()
+ // A scrollable that does not consume the scroll gesture
+ .scrollable(
+ rememberScrollableState(consumeScrollDelta = { 0f }),
+ Orientation.Vertical
+ )
+ .fillMaxSize()
+ ) {
+ Spacer(Modifier.element(TestElements.Foo).fillMaxSize())
+ }
+ }
+ scene(SceneB) { Spacer(Modifier.fillMaxSize()) }
+ }
+ }
+
+ assertThat(state.transitionState).isIdle()
+ val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag)
+ fooElement.assertTopPositionInRootIsEqualTo(0.dp)
+
+ // Swipe down with 2 pointers by half of verticalSwipeDistance.
+ rule.onRoot().performTouchInput {
+ val middleTop = Offset((layoutWidth / 2).toPx(), 0f)
+ repeat(2) { i -> down(pointerId = i, middleTop) }
+ repeat(2) { i ->
+ // Scroll 50%
+ moveBy(
+ pointerId = i,
+ delta = Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f),
+ delayMillis = 1_000,
+ )
+ }
+ }
+
+ val transition = assertThat(state.transitionState).isTransition()
+ assertThat(transition).hasProgress(0.5f)
+ fooElement.assertTopPositionInRootIsEqualTo(translateY * 0.5f)
+ }
+
+ @Test
fun elementTransitionWithDistanceDuringOverscroll() {
val layoutWidth = 200.dp
val layoutHeight = 400.dp
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
index 460b640f0f5f..ecafb170535d 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
@@ -128,7 +128,7 @@ class MultiPointerDraggableTest {
var started = false
var dragged = false
var stopped = false
- var consumeBeforeMultiPointerDraggable = false
+ var consumedByDescendant = false
var touchSlop = 0f
rule.setContent {
@@ -138,6 +138,7 @@ class MultiPointerDraggableTest {
.multiPointerDraggable(
orientation = Orientation.Vertical,
enabled = { true },
+ // We want to start a drag gesture immediately
startDragImmediately = { true },
onDragStarted = { _, _, _ ->
started = true
@@ -157,7 +158,7 @@ class MultiPointerDraggableTest {
awaitPointerEventScope {
while (isActive) {
val change = awaitPointerEvent().changes.first()
- if (consumeBeforeMultiPointerDraggable) {
+ if (consumedByDescendant) {
change.consume()
}
}
@@ -168,18 +169,19 @@ class MultiPointerDraggableTest {
}
// The first part of the gesture is consumed by our descendant
- consumeBeforeMultiPointerDraggable = true
+ consumedByDescendant = true
rule.onRoot().performTouchInput {
down(middle)
moveBy(Offset(0f, touchSlop))
}
- started = false
- dragged = false
- stopped = false
+ // The events were consumed by our descendant, we should not start a drag gesture.
+ assertThat(started).isFalse()
+ assertThat(dragged).isFalse()
+ assertThat(stopped).isFalse()
// The next events could be consumed by us
- consumeBeforeMultiPointerDraggable = false
+ consumedByDescendant = false
rule.onRoot().performTouchInput {
// The pointer is moved to a new position without reporting it
updatePointerBy(0, Offset(0f, touchSlop))
@@ -188,7 +190,7 @@ class MultiPointerDraggableTest {
up()
}
- // This event should not be used to start a drag gesture
+ // The "up" event should not be used to start a drag gesture
assertThat(started).isFalse()
assertThat(dragged).isFalse()
assertThat(stopped).isFalse()
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index de6f1cc518f4..41bf630e9ae4 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -314,7 +314,6 @@ class SceneTransitionLayoutStateTest {
}
},
)
- as MutableSceneTransitionLayoutStateImpl
// Default transition from A to B.
assertThat(state.setTargetScene(SceneB, coroutineScope = this)).isNotNull()
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 86a99e0de5bf..6412276ba34b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -32,11 +32,9 @@ 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;
@@ -46,7 +44,6 @@ 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.statusbar.ui.AmbientStatusBarViewController;
import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController;
@@ -101,9 +98,6 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
ViewGroup mDreamOverlayContentView;
@Mock
- View mHubGestureIndicatorView;
-
- @Mock
Handler mHandler;
@Mock
@@ -158,7 +152,6 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mDreamOverlayContainerView,
mComplicationHostViewController,
mDreamOverlayContentView,
- mHubGestureIndicatorView,
mAmbientStatusBarViewController,
mLowLightTransitionCoordinator,
mTouchInsetSession,
@@ -179,18 +172,6 @@ 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/domain/interactor/KeyguardOcclusionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractorTest.kt
index 0f5e45814608..8914c80cdd5e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractorTest.kt
@@ -41,6 +41,7 @@ import com.android.systemui.authentication.data.repository.fakeAuthenticationRep
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
@@ -54,6 +55,9 @@ import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.scene.data.repository.Transition
+import com.android.systemui.scene.data.repository.setSceneTransition
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -208,6 +212,7 @@ class KeyguardOcclusionInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun showWhenLockedActivityLaunchedFromPowerGesture_falseIfReturningToGone() =
testScope.runTest {
val values by collectValues(underTest.showWhenLockedActivityLaunchedFromPowerGesture)
@@ -245,6 +250,42 @@ class KeyguardOcclusionInteractorTest : SysuiTestCase() {
@Test
@EnableSceneContainer
+ fun showWhenLockedActivityLaunchedFromPowerGesture_falseIfReturningToGone_scene_container() =
+ testScope.runTest {
+ val values by collectValues(underTest.showWhenLockedActivityLaunchedFromPowerGesture)
+ powerInteractor.setAwakeForTest()
+ kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))
+
+ powerInteractor.setAsleepForTest()
+
+ kosmos.setSceneTransition(Transition(Scenes.Gone, Scenes.Lockscreen))
+ transitionRepository.sendTransitionSteps(
+ from = KeyguardState.UNDEFINED,
+ to = KeyguardState.AOD,
+ testScope = testScope,
+ throughTransitionState = TransitionState.RUNNING
+ )
+
+ powerInteractor.onCameraLaunchGestureDetected()
+ kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true)
+ powerInteractor.setAwakeForTest()
+ runCurrent()
+
+ kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))
+ transitionRepository.sendTransitionSteps(
+ from = KeyguardState.AOD,
+ to = KeyguardState.UNDEFINED,
+ testScope = testScope,
+ )
+
+ assertThat(values)
+ .containsExactly(
+ false,
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
fun occludingActivityWillDismissKeyguard() =
testScope.runTest {
val occludingActivityWillDismissKeyguard by
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinatorTest.kt
new file mode 100644
index 000000000000..8a9720ea3cb0
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinatorTest.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.notification.collection.coordinator
+
+import android.app.NotificationChannel
+import android.app.NotificationChannel.NEWS_ID
+import android.app.NotificationChannel.PROMOTIONS_ID
+import android.app.NotificationChannel.RECS_ID
+import android.app.NotificationChannel.SOCIAL_MEDIA_ID
+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
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.render.NodeController
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+class BundleCoordinatorTest : SysuiTestCase() {
+ @Mock private lateinit var newsController: NodeController
+ @Mock private lateinit var socialController: NodeController
+ @Mock private lateinit var recsController: NodeController
+ @Mock private lateinit var promoController: NodeController
+
+ private lateinit var coordinator: BundleCoordinator
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ coordinator =
+ BundleCoordinator(
+ newsController,
+ socialController,
+ recsController,
+ promoController
+ )
+ }
+
+ @Test
+ fun newsSectioner() {
+ assertThat(coordinator.newsSectioner.isInSection(makeEntryOfChannelType(NEWS_ID))).isTrue()
+ assertThat(coordinator.newsSectioner.isInSection(makeEntryOfChannelType("news"))).isFalse()
+ }
+
+ @Test
+ fun socialSectioner() {
+ assertThat(coordinator.socialSectioner.isInSection(makeEntryOfChannelType(SOCIAL_MEDIA_ID)))
+ .isTrue()
+ assertThat(coordinator.socialSectioner.isInSection(makeEntryOfChannelType("social")))
+ .isFalse()
+ }
+
+ @Test
+ fun recsSectioner() {
+ assertThat(coordinator.recsSectioner.isInSection(makeEntryOfChannelType(RECS_ID))).isTrue()
+ assertThat(coordinator.recsSectioner.isInSection(makeEntryOfChannelType("recommendations")))
+ .isFalse()
+ }
+
+ @Test
+ fun promoSectioner() {
+ assertThat(coordinator.promoSectioner.isInSection(makeEntryOfChannelType(PROMOTIONS_ID)))
+ .isTrue()
+ assertThat(coordinator.promoSectioner.isInSection(makeEntryOfChannelType("promo"))).
+ isFalse()
+ }
+
+ private fun makeEntryOfChannelType(
+ type: String,
+ buildBlock: NotificationEntryBuilder.() -> Unit = {}
+ ): NotificationEntry {
+ val channel: NotificationChannel = NotificationChannel(type, type, 2)
+ val entry =
+ NotificationEntryBuilder()
+ .updateRanking {
+ it.setChannel(channel)
+ }
+ .also(buildBlock)
+ .build()
+ return entry
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
index 6b5d07282a08..495ab61600f9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy
import android.app.Notification
+import android.os.Handler
import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper.RunWithLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -59,6 +60,9 @@ class AvalancheControllerTest : SysuiTestCase() {
// For creating TestableHeadsUpManager
@Mock private val mAccessibilityMgr: AccessibilityManagerWrapper? = null
private val mUiEventLoggerFake = UiEventLoggerFake()
+
+ @Mock private lateinit var mBgHandler: Handler
+
private val mLogger = Mockito.spy(HeadsUpManagerLogger(logcatLogBuffer()))
private val mGlobalSettings = FakeGlobalSettings()
private val mSystemClock = FakeSystemClock()
@@ -78,7 +82,7 @@ class AvalancheControllerTest : SysuiTestCase() {
// Initialize AvalancheController and TestableHeadsUpManager during setUp instead of
// declaration, where mocks are null
- mAvalancheController = AvalancheController(dumpManager, mUiEventLoggerFake)
+ mAvalancheController = AvalancheController(dumpManager, mUiEventLoggerFake, mBgHandler)
testableHeadsUpManager =
TestableHeadsUpManager(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 206b39c28da3..df07b446667a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -38,6 +38,7 @@ import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Person;
+import android.os.Handler;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.FlagsParameterization;
@@ -81,7 +82,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase {
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
-
+ @Mock private Handler mBgHandler;
@Mock private DumpManager dumpManager;
private AvalancheController mAvalancheController;
@@ -148,7 +149,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase {
@Override
public void SysuiSetup() throws Exception {
super.SysuiSetup();
- mAvalancheController = new AvalancheController(dumpManager, mUiEventLoggerFake);
+ mAvalancheController = new AvalancheController(dumpManager, mUiEventLoggerFake, mBgHandler);
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
index 7346323f733d..3d3438eab109 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
@@ -104,8 +104,7 @@ public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest {
UiEventLogger uiEventLogger,
JavaAdapter javaAdapter,
ShadeInteractor shadeInteractor,
- AvalancheController avalancheController,
- Handler bgHandler
+ AvalancheController avalancheController
) {
super(
context,
@@ -123,8 +122,7 @@ public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest {
uiEventLogger,
javaAdapter,
shadeInteractor,
- avalancheController,
- bgHandler
+ avalancheController
);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
@@ -147,8 +145,7 @@ public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest {
mUiEventLogger,
mJavaAdapter,
mShadeInteractor,
- mAvalancheController,
- mBgHandler
+ mAvalancheController
);
}
@@ -173,7 +170,7 @@ public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest {
mContext.getOrCreateTestableResources().addOverride(
R.integer.ambient_notification_extension_time, 500);
- mAvalancheController = new AvalancheController(dumpManager, mUiEventLogger);
+ mAvalancheController = new AvalancheController(dumpManager, mUiEventLogger, mBgHandler);
}
@Test
diff --git a/packages/SystemUI/res/drawable/hub_handle.xml b/packages/SystemUI/res/drawable/hub_handle.xml
deleted file mode 100644
index 8bc276ffed9e..000000000000
--- a/packages/SystemUI/res/drawable/hub_handle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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/layout/app_clips_screenshot.xml b/packages/SystemUI/res/layout/app_clips_screenshot.xml
index 6d4e410b3397..b09d35d46ca0 100644
--- a/packages/SystemUI/res/layout/app_clips_screenshot.xml
+++ b/packages/SystemUI/res/layout/app_clips_screenshot.xml
@@ -16,6 +16,7 @@
-->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="@null"
@@ -30,9 +31,10 @@
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:background="@drawable/overlay_button_background"
+ android:backgroundTint="?androidprv:attr/materialColorPrimary"
android:paddingHorizontal="24dp"
android:text="@string/app_clips_save_add_to_note"
- android:textColor="?android:textColorSecondary"
+ android:textColor="?androidprv:attr/materialColorOnPrimary"
app:layout_constraintBottom_toTopOf="@id/preview"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml
index dcd3fa66ef04..be1652b60250 100644
--- a/packages/SystemUI/res/layout/dream_overlay_container.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_container.xml
@@ -21,19 +21,6 @@
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/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt
index 6032f0b7b618..b33924ca0b70 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt
@@ -18,10 +18,10 @@ package com.android.systemui.accessibility.data.repository
import android.view.accessibility.AccessibilityManager
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
-import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import com.android.app.tracing.FlowTracing.tracedAwaitClose
+import com.android.app.tracing.FlowTracing.tracedConflatedCallbackFlow
import dagger.Module
import dagger.Provides
-import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -38,24 +38,28 @@ interface AccessibilityRepository {
}
}
+private const val TAG = "AccessibilityRepository"
+
private class AccessibilityRepositoryImpl(
manager: AccessibilityManager,
) : AccessibilityRepository {
override val isTouchExplorationEnabled: Flow<Boolean> =
- conflatedCallbackFlow {
+ tracedConflatedCallbackFlow(TAG) {
val listener = TouchExplorationStateChangeListener(::trySend)
manager.addTouchExplorationStateChangeListener(listener)
trySend(manager.isTouchExplorationEnabled)
- awaitClose { manager.removeTouchExplorationStateChangeListener(listener) }
+ tracedAwaitClose(TAG) {
+ manager.removeTouchExplorationStateChangeListener(listener)
+ }
}
.distinctUntilChanged()
override val isEnabled: Flow<Boolean> =
- conflatedCallbackFlow {
+ tracedConflatedCallbackFlow(TAG) {
val listener = AccessibilityManager.AccessibilityStateChangeListener(::trySend)
manager.addAccessibilityStateChangeListener(listener)
trySend(manager.isEnabled)
- awaitClose { manager.removeAccessibilityStateChangeListener(listener) }
+ tracedAwaitClose(TAG) { manager.removeAccessibilityStateChangeListener(listener) }
}
.distinctUntilChanged()
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index d6d40f28d288..b466f31cc509 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -995,6 +995,16 @@ public class AuthController implements
}
/**
+ * @return true if ultrasonic udfps HW is supported on this device. Can return true even if
+ * the user has not enrolled udfps. This may be false if called before
+ * onAllAuthenticatorsRegistered.
+ */
+ public boolean isUltrasonicUdfpsSupported() {
+ return getUdfpsProps() != null && !getUdfpsProps().isEmpty() && getUdfpsProps()
+ .get(0).isUltrasonicUdfps();
+ }
+
+ /**
* @return true if sfps HW is supported on this device. Can return true even if the user has
* not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 9d3c6a49a616..3dd375846499 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -270,6 +270,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
@Override
public void showUdfpsOverlay(long requestId, int sensorId, int reason,
@NonNull IUdfpsOverlayControllerCallback callback) {
+ mUdfpsOverlayInteractor.setRequestId(requestId);
mFgExecutor.execute(() -> UdfpsController.this.showUdfpsOverlay(
new UdfpsControllerOverlay(
mContext,
@@ -404,6 +405,15 @@ public class UdfpsController implements DozeReceiver, Dumpable {
handler::post,
authenticationCallback);
}
+
+ /**
+ * Debug to run setIgnoreDisplayTouches
+ */
+ public void debugSetIgnoreDisplayTouches(boolean ignoreTouch) {
+ final long requestId = (mOverlay != null) ? mOverlay.getRequestId() : 0L;
+ UdfpsController.this.mFingerprintManager.setIgnoreDisplayTouches(
+ requestId, mSensorProps.sensorId, ignoreTouch);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
index f5e3d29cb878..97ece11b8fbb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
@@ -75,6 +75,8 @@ class UdfpsShell @Inject constructor(commandRegistry: CommandRegistry) : Command
simFingerUp()
} else if (args.size == 1 && args[0] == "biometricPrompt") {
launchBiometricPrompt()
+ } else if (args.size == 2 && args[0] == "setIgnoreDisplayTouches") {
+ setIgnoreDisplayTouches(args[1].toBoolean())
} else {
invalidCommand(pw)
}
@@ -186,6 +188,11 @@ class UdfpsShell @Inject constructor(commandRegistry: CommandRegistry) : Command
upEvent?.recycle()
}
+ @VisibleForTesting
+ fun setIgnoreDisplayTouches(ignoreTouches: Boolean) {
+ udfpsOverlayController?.debugSetIgnoreDisplayTouches(ignoreTouches)
+ }
+
private fun obtainMotionEvent(
action: Int,
x: Float,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
index a77cc1fea6a6..bb450c0b6d90 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.domain.interactor
import android.content.Context
+import android.hardware.fingerprint.FingerprintManager
import android.util.Log
import android.view.MotionEvent
import com.android.systemui.biometrics.AuthController
@@ -46,6 +47,7 @@ constructor(
@Application private val context: Context,
private val authController: AuthController,
private val selectedUserInteractor: SelectedUserInteractor,
+ private val fingerprintManager: FingerprintManager?,
@Application scope: CoroutineScope
) {
private fun calculateIconSize(): Int {
@@ -70,8 +72,25 @@ constructor(
return isUdfpsEnrolled && isWithinOverlayBounds
}
+ private var _requestId = MutableStateFlow(0L)
+
+ /** RequestId of current AcquisitionClient */
+ val requestId: StateFlow<Long> = _requestId.asStateFlow()
+
+ fun setRequestId(requestId: Long) {
+ _requestId.value = requestId
+ }
+
/** Sets whether Udfps overlay should handle touches */
fun setHandleTouches(shouldHandle: Boolean = true) {
+ if (authController.isUltrasonicUdfpsSupported
+ && shouldHandle != _shouldHandleTouches.value) {
+ fingerprintManager?.setIgnoreDisplayTouches(
+ requestId.value,
+ authController.udfpsProps!!.get(0).sensorId,
+ !shouldHandle
+ )
+ }
_shouldHandleTouches.value = shouldHandle
}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
index f991d5b8405f..8270db1e89a8 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
@@ -16,7 +16,7 @@
package com.android.systemui.brightness.ui.compose
-import androidx.compose.animation.core.animateIntAsState
+import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
@@ -57,12 +57,12 @@ private fun BrightnessSlider(
) {
var value by remember(gammaValue) { mutableIntStateOf(gammaValue) }
val animatedValue by
- animateIntAsState(targetValue = value, label = "BrightnessSliderAnimatedValue")
+ animateFloatAsState(targetValue = value.toFloat(), label = "BrightnessSliderAnimatedValue")
val floatValueRange = valueRange.first.toFloat()..valueRange.last.toFloat()
- val isRestricted = restriction is PolicyRestriction.Restricted
+ val isRestricted = remember(restriction) { restriction is PolicyRestriction.Restricted }
PlatformSlider(
- value = animatedValue.toFloat(),
+ value = animatedValue,
valueRange = floatValueRange,
enabled = !isRestricted,
onValueChange = {
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 f9f01f70e2dd..780bf70f3f7b 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
@@ -322,14 +322,6 @@ constructor(
not(shadeInteractor.isAnyFullyExpanded)
.stateIn(bgScope, SharingStarted.Eagerly, initialValue = false)
- // 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)
-
/** The type of background to use for the hub. */
val communalBackground: Flow<CommunalBackgroundType> =
communalSettingsInteractor.communalBackground
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 4fd1c24dfa67..76c7d2383751 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -21,8 +21,6 @@ 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;
@@ -192,7 +190,6 @@ public class DreamOverlayContainerViewController extends
DreamOverlayContainerView containerView,
ComplicationHostViewController complicationHostViewController,
@Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
- @Named(DreamOverlayModule.HUB_GESTURE_INDICATOR_VIEW) View hubGestureIndicatorView,
AmbientStatusBarViewController statusBarViewController,
LowLightTransitionCoordinator lowLightTransitionCoordinator,
TouchInsetManager.TouchInsetSession touchInsetSession,
@@ -230,12 +227,6 @@ 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 76fcabd635d8..12984efb52c2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -18,7 +18,6 @@ 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;
@@ -42,7 +41,6 @@ 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";
@@ -75,18 +73,6 @@ 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/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
index f54fd2269679..b47fb65ae9e8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
@@ -16,12 +16,18 @@
package com.android.systemui.keyboard.shortcut.data.repository
+import android.content.Context
+import android.hardware.input.InputManager
+import android.util.Log
+import android.view.InputDevice
+import android.view.KeyCharacterMap
import android.view.KeyEvent
import android.view.KeyboardShortcutGroup
import android.view.KeyboardShortcutInfo
import android.view.WindowManager
import android.view.WindowManager.KeyboardShortcutsReceiver
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.shortcut.data.source.KeyboardShortcutGroupsSource
import com.android.systemui.keyboard.shortcut.qualifiers.MultitaskingShortcuts
import com.android.systemui.keyboard.shortcut.qualifiers.SystemShortcuts
@@ -30,29 +36,46 @@ import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.IME
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MULTI_TASKING
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.SYSTEM
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
@SysUISingleton
class ShortcutHelperCategoriesRepository
@Inject
constructor(
+ private val context: Context,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
@SystemShortcuts private val systemShortcutsSource: KeyboardShortcutGroupsSource,
@MultitaskingShortcuts private val multitaskingShortcutsSource: KeyboardShortcutGroupsSource,
private val windowManager: WindowManager,
- shortcutHelperStateRepository: ShortcutHelperStateRepository
+ private val inputManager: InputManager,
+ stateRepository: ShortcutHelperStateRepository
) {
- val systemShortcutsCategory =
- shortcutHelperStateRepository.state.map {
+ private val activeInputDevice =
+ stateRepository.state.map {
if (it is Active) {
+ withContext(backgroundDispatcher) { inputManager.getInputDevice(it.deviceId) }
+ } else {
+ null
+ }
+ }
+
+ val systemShortcutsCategory =
+ activeInputDevice.map {
+ if (it != null) {
toShortcutCategory(
- systemShortcutsSource.shortcutGroups(),
- ShortcutCategoryType.SYSTEM
+ it.keyCharacterMap,
+ SYSTEM,
+ systemShortcutsSource.shortcutGroups()
)
} else {
null
@@ -60,76 +83,128 @@ constructor(
}
val multitaskingShortcutsCategory =
- shortcutHelperStateRepository.state.map {
- if (it is Active) {
- toShortcutCategory(multitaskingShortcutsSource.shortcutGroups(), MULTI_TASKING)
+ activeInputDevice.map {
+ if (it != null) {
+ toShortcutCategory(
+ it.keyCharacterMap,
+ MULTI_TASKING,
+ multitaskingShortcutsSource.shortcutGroups()
+ )
} else {
null
}
}
val imeShortcutsCategory =
- shortcutHelperStateRepository.state.map {
- if (it is Active) retrieveImeShortcuts(it.deviceId) else null
- }
+ activeInputDevice.map { if (it != null) retrieveImeShortcuts(it) else null }
- private suspend fun retrieveImeShortcuts(deviceId: Int): ShortcutCategory? {
+ private suspend fun retrieveImeShortcuts(
+ inputDevice: InputDevice,
+ ): ShortcutCategory? {
return suspendCancellableCoroutine { continuation ->
val shortcutsReceiver = KeyboardShortcutsReceiver { shortcutGroups ->
- continuation.resumeWith(Result.success(toShortcutCategory(shortcutGroups, IME)))
+ continuation.resumeWith(
+ Result.success(
+ toShortcutCategory(inputDevice.keyCharacterMap, IME, shortcutGroups)
+ )
+ )
}
- windowManager.requestImeKeyboardShortcuts(shortcutsReceiver, deviceId)
+ windowManager.requestImeKeyboardShortcuts(shortcutsReceiver, inputDevice.id)
}
}
private fun toShortcutCategory(
- shortcutGroups: List<KeyboardShortcutGroup>,
+ keyCharacterMap: KeyCharacterMap,
type: ShortcutCategoryType,
+ shortcutGroups: List<KeyboardShortcutGroup>,
): ShortcutCategory? {
val subCategories =
shortcutGroups
.map { shortcutGroup ->
ShortcutSubCategory(
- label = shortcutGroup.label.toString(),
- shortcuts = toShortcuts(shortcutGroup.items)
+ shortcutGroup.label.toString(),
+ toShortcuts(keyCharacterMap, shortcutGroup.items)
)
}
.filter { it.shortcuts.isNotEmpty() }
return if (subCategories.isEmpty()) {
+ Log.wtf(TAG, "Empty sub categories after converting $shortcutGroups")
null
} else {
ShortcutCategory(type, subCategories)
}
}
- private fun toShortcuts(infoList: List<KeyboardShortcutInfo>) =
- infoList.mapNotNull { toShortcut(it) }
+ private fun toShortcuts(
+ keyCharacterMap: KeyCharacterMap,
+ infoList: List<KeyboardShortcutInfo>
+ ) = infoList.mapNotNull { toShortcut(keyCharacterMap, it) }
- private fun toShortcut(shortcutInfo: KeyboardShortcutInfo): Shortcut? {
- val shortcutCommand = toShortcutCommand(shortcutInfo)
+ private fun toShortcut(
+ keyCharacterMap: KeyCharacterMap,
+ shortcutInfo: KeyboardShortcutInfo
+ ): Shortcut? {
+ val shortcutCommand = toShortcutCommand(keyCharacterMap, shortcutInfo)
return if (shortcutCommand == null) null
else Shortcut(label = shortcutInfo.label!!.toString(), commands = listOf(shortcutCommand))
}
- private fun toShortcutCommand(info: KeyboardShortcutInfo): ShortcutCommand? {
- val keyCodes = mutableListOf<Int>()
+ private fun toShortcutCommand(
+ keyCharacterMap: KeyCharacterMap,
+ info: KeyboardShortcutInfo
+ ): ShortcutCommand? {
+ val keys = mutableListOf<ShortcutKey>()
var remainingModifiers = info.modifiers
SUPPORTED_MODIFIERS.forEach { supportedModifier ->
if ((supportedModifier and remainingModifiers) != 0) {
- keyCodes += supportedModifier
+ keys += toShortcutKey(keyCharacterMap, supportedModifier) ?: return null
// "Remove" the modifier from the remaining modifiers
remainingModifiers = remainingModifiers and supportedModifier.inv()
}
}
if (remainingModifiers != 0) {
// There is a remaining modifier we don't support
+ Log.wtf(TAG, "Unsupported modifiers remaining: $remainingModifiers")
return null
}
- keyCodes += info.keycode
- return ShortcutCommand(keyCodes)
+ if (info.keycode != 0) {
+ keys += toShortcutKey(keyCharacterMap, info.keycode, info.baseCharacter) ?: return null
+ }
+ if (keys.isEmpty()) {
+ Log.wtf(TAG, "No keys for $info")
+ return null
+ }
+ return ShortcutCommand(keys)
+ }
+
+ private fun toShortcutKey(
+ keyCharacterMap: KeyCharacterMap,
+ keyCode: Int,
+ baseCharacter: Char = Char.MIN_VALUE,
+ ): ShortcutKey? {
+ val iconResId = ShortcutHelperKeys.keyIcons[keyCode]
+ if (iconResId != null) {
+ return ShortcutKey.Icon(iconResId)
+ }
+ if (baseCharacter > Char.MIN_VALUE) {
+ return ShortcutKey.Text(baseCharacter.toString())
+ }
+ val specialKeyLabel = ShortcutHelperKeys.specialKeyLabels[keyCode]
+ if (specialKeyLabel != null) {
+ val label = specialKeyLabel(context)
+ return ShortcutKey.Text(label)
+ }
+ val displayLabelCharacter = keyCharacterMap.getDisplayLabel(keyCode)
+ if (displayLabelCharacter.code != 0) {
+ return ShortcutKey.Text(displayLabelCharacter.toString())
+ }
+ Log.wtf(TAG, "Couldn't find label or icon for key: $keyCode")
+ return null
}
companion object {
+ private const val TAG = "SHCategoriesRepo"
+
private val SUPPORTED_MODIFIERS =
listOf(
KeyEvent.META_META_ON,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
index e5b870a983c6..adc6d952f2c3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
@@ -21,8 +21,8 @@ data class Shortcut(val label: String, val commands: List<ShortcutCommand>)
class ShortcutBuilder(private val label: String) {
val commands = mutableListOf<ShortcutCommand>()
- fun command(vararg keyCodes: Int) {
- commands += ShortcutCommand(keyCodes.toList())
+ fun command(builder: ShortcutCommandBuilder.() -> Unit) {
+ commands += ShortcutCommandBuilder().apply(builder).build()
}
fun build() = Shortcut(label, commands)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
index 3ac7fa8f8ece..5d0535905540 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
@@ -30,8 +30,8 @@ data class ShortcutCategory(
class ShortcutCategoryBuilder(val type: ShortcutCategoryType) {
private val subCategories = mutableListOf<ShortcutSubCategory>()
- fun subCategory(label: String, shortcuts: List<Shortcut>) {
- subCategories += ShortcutSubCategory(label, shortcuts)
+ fun subCategory(label: String, builder: ShortcutSubCategoryBuilder.() -> Unit) {
+ subCategories += ShortcutSubCategoryBuilder(label).apply(builder).build()
}
fun build() = ShortcutCategory(type, subCategories)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
index a98a8ffb7004..e5b8096f2403 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
@@ -16,4 +16,23 @@
package com.android.systemui.keyboard.shortcut.shared.model
-data class ShortcutCommand(val keyCodes: List<Int>)
+import androidx.annotation.DrawableRes
+
+data class ShortcutCommand(val keys: List<ShortcutKey>)
+
+class ShortcutCommandBuilder {
+ private val keys = mutableListOf<ShortcutKey>()
+
+ fun key(text: String) {
+ keys += ShortcutKey.Text(text)
+ }
+
+ fun key(@DrawableRes drawableResId: Int) {
+ keys += ShortcutKey.Icon(drawableResId)
+ }
+
+ fun build() = ShortcutCommand(keys)
+}
+
+fun shortcutCommand(block: ShortcutCommandBuilder.() -> Unit) =
+ ShortcutCommandBuilder().apply(block).build()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt
new file mode 100644
index 000000000000..1abb78c54b99
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.keyboard.shortcut.shared.model
+
+import androidx.annotation.DrawableRes
+
+sealed interface ShortcutKey {
+ data class Text(val value: String) : ShortcutKey
+
+ data class Icon(@DrawableRes val drawableResId: Int) : ShortcutKey
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
index 4545b4c5dd28..14016783a478 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
@@ -17,3 +17,13 @@
package com.android.systemui.keyboard.shortcut.shared.model
data class ShortcutSubCategory(val label: String, val shortcuts: List<Shortcut>)
+
+class ShortcutSubCategoryBuilder(val label: String) {
+ private val shortcuts = mutableListOf<Shortcut>()
+
+ fun shortcut(label: String, builder: ShortcutBuilder.() -> Unit) {
+ shortcuts += ShortcutBuilder(label).apply(builder).build()
+ }
+
+ fun build() = ShortcutSubCategory(label, shortcuts)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 5f6fe1c2130d..b32d0950e0d2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -27,6 +27,7 @@ import android.os.DeadObjectException
import android.os.Handler
import android.os.PowerManager
import android.os.RemoteException
+import android.os.Trace
import android.util.Log
import android.view.RemoteAnimationTarget
import android.view.SurfaceControl
@@ -385,10 +386,15 @@ class KeyguardUnlockAnimationController @Inject constructor(
valueAnimator.animatedValue as Float, openingWallpaperTargets)
}
addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator) {
+ super.onAnimationStart(animation)
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, "WallpaperAlphaAnimation", 0)
+ }
override fun onAnimationEnd(animation: Animator) {
Log.d(TAG, "wallpaperCannedUnlockAnimator#onAnimationEnd")
keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation(
false /* cancelled */)
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, "WallpaperAlphaAnimation", 0)
}
})
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt
index e9bd88932c52..e6bab4c7edcf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt
@@ -19,8 +19,9 @@ package com.android.systemui.keyguard.data.quickaffordance
import android.content.Context
import android.os.UserHandle
+import com.android.app.tracing.FlowTracing.tracedAwaitClose
+import com.android.app.tracing.FlowTracing.tracedConflatedCallbackFlow
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.settings.UserTracker
@@ -28,7 +29,6 @@ import com.android.systemui.shared.customization.data.content.CustomizationProvi
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -55,19 +55,20 @@ constructor(
private val userHandle: UserHandle,
) : KeyguardQuickAffordanceSelectionManager {
- private val userId: Flow<Int> = conflatedCallbackFlow {
- val callback =
- object : UserTracker.Callback {
- override fun onUserChanged(newUser: Int, userContext: Context) {
- trySendWithFailureLogging(newUser, TAG)
+ private val userId: Flow<Int> =
+ tracedConflatedCallbackFlow("userId") {
+ val callback =
+ object : UserTracker.Callback {
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ trySendWithFailureLogging(newUser, TAG)
+ }
}
- }
- userTracker.addCallback(callback) { it.run() }
- trySendWithFailureLogging(userTracker.userId, TAG)
+ userTracker.addCallback(callback) { it.run() }
+ trySendWithFailureLogging(userTracker.userId, TAG)
- awaitClose { userTracker.removeCallback(callback) }
- }
+ tracedAwaitClose("userId") { userTracker.removeCallback(callback) }
+ }
private val clientOrNull: StateFlow<CustomizationProviderClient?> =
userId
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 63dd255c5de4..f837d8efdcc5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -62,6 +62,7 @@ import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Defines interface for classes that encapsulate application state for the keyguard. */
interface KeyguardRepository {
@@ -362,30 +363,8 @@ constructor(
override val topClippingBounds = MutableStateFlow<Int?>(null)
- override val isKeyguardShowing: Flow<Boolean> =
- conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onKeyguardShowingChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isShowing,
- TAG,
- "updated isKeyguardShowing"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isShowing,
- TAG,
- "initial isKeyguardShowing"
- )
-
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
- .distinctUntilChanged()
+ override val isKeyguardShowing: MutableStateFlow<Boolean> =
+ MutableStateFlow(keyguardStateController.isShowing)
private val _isAodAvailable = MutableStateFlow(false)
override val isAodAvailable: StateFlow<Boolean> = _isAodAvailable.asStateFlow()
@@ -394,91 +373,14 @@ constructor(
_isAodAvailable.value = value
}
- override val isKeyguardOccluded: Flow<Boolean> =
- conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onKeyguardShowingChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isOccluded,
- TAG,
- "updated isKeyguardOccluded"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isOccluded,
- TAG,
- "initial isKeyguardOccluded"
- )
-
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
- .distinctUntilChanged()
-
- override val isKeyguardDismissible: StateFlow<Boolean> =
- conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onUnlockedChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "updated isKeyguardDismissible due to onUnlockedChanged"
- )
- }
-
- override fun onKeyguardShowingChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "updated isKeyguardDismissible due to onKeyguardShowingChanged"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "initial isKeyguardUnlocked"
- )
+ override val isKeyguardOccluded: MutableStateFlow<Boolean> =
+ MutableStateFlow(keyguardStateController.isOccluded)
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
- .distinctUntilChanged()
- .stateIn(
- scope,
- SharingStarted.Eagerly,
- initialValue = false,
- )
+ override val isKeyguardDismissible: MutableStateFlow<Boolean> =
+ MutableStateFlow(keyguardStateController.isUnlocked)
- override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onKeyguardGoingAwayChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isKeyguardGoingAway,
- TAG,
- "updated isKeyguardGoingAway"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isKeyguardGoingAway,
- TAG,
- "initial isKeyguardGoingAway"
- )
-
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
+ override val isKeyguardGoingAway: MutableStateFlow<Boolean> =
+ MutableStateFlow(keyguardStateController.isKeyguardGoingAway)
private val _isKeyguardEnabled =
MutableStateFlow(!lockPatternUtils.isLockScreenDisabled(userTracker.userId))
@@ -669,6 +571,35 @@ constructor(
private val _isActiveDreamLockscreenHosted = MutableStateFlow(false)
override val isActiveDreamLockscreenHosted = _isActiveDreamLockscreenHosted.asStateFlow()
+ init {
+ val callback =
+ object : KeyguardStateController.Callback {
+ override fun onKeyguardShowingChanged() {
+ isKeyguardShowing.value = keyguardStateController.isShowing
+ isKeyguardOccluded.value = keyguardStateController.isOccluded
+ isKeyguardDismissible.value = keyguardStateController.isUnlocked
+ }
+
+ override fun onUnlockedChanged() {
+ isKeyguardDismissible.value = keyguardStateController.isUnlocked
+ }
+
+ override fun onKeyguardGoingAwayChanged() {
+ isKeyguardGoingAway.value = keyguardStateController.isKeyguardGoingAway
+ }
+ }
+
+ keyguardStateController.addCallback(callback)
+
+ scope
+ .launch {
+ isKeyguardShowing.collect {
+ // no-op to allow for callback removal
+ }
+ }
+ .invokeOnCompletion { keyguardStateController.removeCallback(callback) }
+ }
+
override fun setAnimateDozingTransitions(animate: Boolean) {
_animateBottomAreaDozingTransitions.value = animate
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 3877e7ae1e55..76e88a2a2cd6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -28,6 +28,7 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor
import com.android.systemui.keyguard.shared.model.BiometricUnlockMode.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.Utils.Companion.sample
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
@@ -100,10 +101,14 @@ constructor(
biometricUnlockState,
) ->
if (isWakeAndUnlock(biometricUnlockState.mode)) {
- startTransitionTo(
- KeyguardState.GONE,
- ownerReason = "biometric wake and unlock",
- )
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ } else {
+ startTransitionTo(
+ KeyguardState.GONE,
+ ownerReason = "biometric wake and unlock",
+ )
+ }
}
}
}
@@ -131,21 +136,35 @@ constructor(
isIdleOnCommunal,
canTransitionToGoneOnWake,
primaryBouncerShowing) ->
- startTransitionTo(
- if (!deviceEntryRepository.isLockscreenEnabled()) {
- KeyguardState.GONE
- } else if (canTransitionToGoneOnWake) {
- KeyguardState.GONE
- } else if (primaryBouncerShowing) {
- KeyguardState.PRIMARY_BOUNCER
- } else if (occluded) {
- KeyguardState.OCCLUDED
- } else if (isIdleOnCommunal) {
- KeyguardState.GLANCEABLE_HUB
+ if (!deviceEntryRepository.isLockscreenEnabled()) {
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ } else {
+ startTransitionTo(KeyguardState.GONE)
+ }
+ } else if (canTransitionToGoneOnWake) {
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ } else {
+ startTransitionTo(KeyguardState.GONE)
+ }
+ } else if (primaryBouncerShowing) {
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ } else {
+ startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
+ }
+ } else if (occluded) {
+ startTransitionTo(KeyguardState.OCCLUDED)
+ } else if (isIdleOnCommunal) {
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
} else {
- KeyguardState.LOCKSCREEN
+ startTransitionTo(KeyguardState.GLANCEABLE_HUB)
}
- )
+ } else {
+ startTransitionTo(KeyguardState.LOCKSCREEN)
+ }
}
}
}
@@ -177,23 +196,55 @@ constructor(
// Handled by dismissFromDozing().
!isWakeAndUnlock(biometricUnlockState.mode)
) {
- startTransitionTo(
- if (!KeyguardWmStateRefactor.isEnabled && canDismissLockscreen) {
- KeyguardState.GONE
- } else if (
- KeyguardWmStateRefactor.isEnabled &&
- !deviceEntryRepository.isLockscreenEnabled()
- ) {
- KeyguardState.GONE
- } else if (primaryBouncerShowing) {
- KeyguardState.PRIMARY_BOUNCER
- } else if (isIdleOnCommunal) {
- KeyguardState.GLANCEABLE_HUB
+ if (!KeyguardWmStateRefactor.isEnabled && canDismissLockscreen) {
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is
+ // needed
+ } else {
+ startTransitionTo(
+ KeyguardState.GONE,
+ ownerReason = "waking from dozing"
+ )
+ }
+ } else if (
+ KeyguardWmStateRefactor.isEnabled &&
+ !deviceEntryRepository.isLockscreenEnabled()
+ ) {
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is
+ // needed
+ } else {
+ startTransitionTo(
+ KeyguardState.GONE,
+ ownerReason = "waking from dozing"
+ )
+ }
+ } else if (primaryBouncerShowing) {
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is
+ // needed
} else {
- KeyguardState.LOCKSCREEN
- },
- ownerReason = "waking from dozing"
- )
+ startTransitionTo(
+ KeyguardState.PRIMARY_BOUNCER,
+ ownerReason = "waking from dozing"
+ )
+ }
+ } else if (isIdleOnCommunal) {
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is
+ // needed
+ } else {
+ startTransitionTo(
+ KeyguardState.GLANCEABLE_HUB,
+ ownerReason = "waking from dozing"
+ )
+ }
+ } else {
+ startTransitionTo(
+ KeyguardState.LOCKSCREEN,
+ ownerReason = "waking from dozing"
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 97006486b6f1..0e764879d8f6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -91,8 +91,8 @@ constructor(
private fun listenForDreamingToGlanceableHub() {
if (!communalHub()) return
- if (SceneContainerFlag.isEnabled)
- return // TODO(b/336576536): Check if adaptation for scene framework is needed
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch("$TAG#listenForDreamingToGlanceableHub", mainDispatcher) {
glanceableHubTransitions.listenForGlanceableHubTransition(
transitionOwnerName = TAG,
@@ -103,6 +103,8 @@ constructor(
}
private fun listenForDreamingToPrimaryBouncer() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.primaryBouncerShowing
.sample(startedKeyguardTransitionStep, ::Pair)
@@ -179,8 +181,8 @@ constructor(
}
private fun listenForDreamingToGoneWhenDismissable() {
- if (SceneContainerFlag.isEnabled)
- return // TODO(b/336576536): Check if adaptation for scene framework is needed
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.isAbleToDream
.sampleCombine(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 22ab82b383a7..859326a29b28 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -23,9 +23,10 @@ import android.app.StatusBarManager
import android.graphics.Point
import android.util.MathUtils
import com.android.app.animation.Interpolators
+import com.android.app.tracing.FlowTracing.tracedAwaitClose
+import com.android.app.tracing.FlowTracing.tracedConflatedCallbackFlow
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.dagger.SysUISingleton
@@ -51,13 +52,13 @@ import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.notification.NotificationUtils.interpolate
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
+import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -197,22 +198,22 @@ constructor(
val isActiveDreamLockscreenHosted: StateFlow<Boolean> = repository.isActiveDreamLockscreenHosted
/** Event for when the camera gesture is detected */
- val onCameraLaunchDetected: Flow<CameraLaunchSourceModel> = conflatedCallbackFlow {
- val callback =
- object : CommandQueue.Callbacks {
- override fun onCameraLaunchGestureDetected(source: Int) {
- trySendWithFailureLogging(
- cameraLaunchSourceIntToModel(source),
- TAG,
- "updated onCameraLaunchGestureDetected"
- )
+ val onCameraLaunchDetected: Flow<CameraLaunchSourceModel> =
+ tracedConflatedCallbackFlow("KeyguardInteractor#onCameraLaunchDetected") {
+ val callback =
+ object : CommandQueue.Callbacks {
+ override fun onCameraLaunchGestureDetected(source: Int) {
+ trySendWithFailureLogging(
+ cameraLaunchSourceIntToModel(source),
+ TAG,
+ "updated onCameraLaunchGestureDetected")
+ }
}
- }
- commandQueue.addCallback(callback)
+ commandQueue.addCallback(callback)
- awaitClose { commandQueue.removeCallback(callback) }
- }
+ tracedAwaitClose("onCameraLaunchDetected") { commandQueue.removeCallback(callback) }
+ }
/**
* Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means
@@ -250,17 +251,13 @@ constructor(
/** Keyguard can be clipped at the top as the shade is dragged */
val topClippingBounds: Flow<Int?> by lazy {
- combineTransform(
+ repository.topClippingBounds
+ .sampleFilter(
keyguardTransitionInteractor
.transitionValue(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
- .map { it == 1f }
- .onStart { emit(false) }
- .distinctUntilChanged(),
- repository.topClippingBounds
- ) { isGone, topClippingBounds ->
- if (!isGone) {
- emit(topClippingBounds)
- }
+ .onStart { emit(0f) }
+ ) { goneValue ->
+ goneValue != 1f
}
.distinctUntilChanged()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt
index 41ccea735f5f..5af38ba49b85 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt
@@ -24,6 +24,7 @@ import com.android.systemui.keyguard.data.repository.KeyguardOcclusionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.util.kotlin.sample
import dagger.Lazy
import javax.inject.Inject
@@ -94,10 +95,15 @@ constructor(
// currently
// GONE, in which case we're going back to GONE and launching the insecure camera).
powerInteractor.detailedWakefulness
- .sample(transitionInteractor.currentKeyguardState, ::Pair)
- .map { (wakefulness, currentKeyguardState) ->
- wakefulness.powerButtonLaunchGestureTriggered &&
- currentKeyguardState != KeyguardState.GONE
+ .sample(
+ transitionInteractor.isFinishedIn(
+ Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE
+ ),
+ ::Pair
+ )
+ .map { (wakefulness, isOnGone) ->
+ wakefulness.powerButtonLaunchGestureTriggered && !isOnGone
},
// Emit false once that activity goes away.
isShowWhenLockedActivityOnTop.filter { !it }.map { false }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
index 82255a0c0d54..bcbdc9cca83b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
@@ -19,9 +19,10 @@ package com.android.systemui.keyguard.domain.interactor
import android.content.Context
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository
-import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor.Companion.isSurfaceVisible
+import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.kotlin.toPx
@@ -56,12 +57,18 @@ constructor(
*/
val viewParams: Flow<KeyguardSurfaceBehindModel> =
combine(
- transitionInteractor.startedKeyguardTransitionStep,
- transitionInteractor.currentKeyguardState,
+ transitionInteractor.isInTransition(
+ Edge.create(to = Scenes.Gone),
+ edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GONE)
+ ),
+ transitionInteractor.isFinishedIn(
+ Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE
+ ),
notificationLaunchInteractor.isLaunchAnimationRunning,
- ) { startedStep, currentState, notifAnimationRunning ->
+ ) { transitioningToGone, isOnGone, notifAnimationRunning ->
// If we're in transition to GONE, special unlock animation params apply.
- if (startedStep.to == KeyguardState.GONE && currentState != KeyguardState.GONE) {
+ if (transitioningToGone) {
if (notifAnimationRunning) {
// If the notification launch animation is running, leave the alpha at 0f.
// The ActivityLaunchAnimator will morph it from the notification at the
@@ -87,14 +94,14 @@ constructor(
animateFromTranslationY =
SURFACE_TRANSLATION_Y_DISTANCE_DP.toPx(context).toFloat(),
translationY = 0f,
- startVelocity = swipeToDismissInteractor.dismissFling.value?.velocity
- ?: 0f,
+ startVelocity =
+ swipeToDismissInteractor.dismissFling.value?.velocity ?: 0f,
)
}
}
// Default to the visibility of the current state, with no animations.
- KeyguardSurfaceBehindModel(alpha = if (isSurfaceVisible(currentState)) 1f else 0f)
+ KeyguardSurfaceBehindModel(alpha = if (isOnGone) 1f else 0f)
}
.distinctUntilChanged()
@@ -103,10 +110,14 @@ constructor(
*/
private val isNotificationLaunchAnimationRunningOnKeyguard =
notificationLaunchInteractor.isLaunchAnimationRunning
- .sample(transitionInteractor.finishedKeyguardState, ::Pair)
- .map { (animationRunning, finishedState) ->
- animationRunning && finishedState != KeyguardState.GONE
- }
+ .sample(
+ transitionInteractor.isFinishedIn(
+ Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE
+ ),
+ ::Pair
+ )
+ .map { (animationRunning, isOnGone) -> animationRunning && !isOnGone }
.onStart { emit(false) }
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
index b3c9591f5668..805dbb08d1ac 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
@@ -22,7 +22,10 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -57,17 +60,7 @@ constructor(
override fun start() {
scope.launch {
- val state =
- if (showLockscreenOnBoot.first()) {
- KeyguardState.LOCKSCREEN
- } else {
- KeyguardState.GONE
- }
-
- if (
- internalTransitionInteractor.currentTransitionInfoInternal.value.from !=
- KeyguardState.OFF
- ) {
+ if (internalTransitionInteractor.currentTransitionInfoInternal.value.from != OFF) {
Log.e(
"KeyguardTransitionInteractor",
"showLockscreenOnBoot emitted, but we've already " +
@@ -75,7 +68,23 @@ constructor(
"transition, but this should not happen."
)
} else {
- repository.emitInitialStepsFromOff(state)
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Some part of the transition implemented for flag off is
+ // missing here. There are two things achieved with this:
+ // 1. Keyguard is hidden when the setup wizard is shown. This part is already
+ // implemented in scene container by disabling visibility instead of going
+ // to Gone. See [SceneContainerStartable.hydrateVisibility]. We might want
+ // to unify this logic here.
+ // 2. When the auth method is set to NONE device boots into Gone (Launcher).
+ // For this we would just need to call changeScene(Scene.Gone).
+ // Unfortunately STL doesn't seem to be initialized at this point, therefore
+ // it needs a different solution.
+ repository.emitInitialStepsFromOff(LOCKSCREEN)
+ } else {
+ repository.emitInitialStepsFromOff(
+ if (showLockscreenOnBoot.first()) LOCKSCREEN else GONE
+ )
+ }
}
}
}
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 973e8989b82a..bbc3d7699dee 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
@@ -25,6 +25,7 @@ import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.sample
import java.util.UUID
import kotlinx.coroutines.CoroutineDispatcher
@@ -81,6 +82,7 @@ sealed class TransitionInteractor(
// a bugreport.
ownerReason: String = "",
): UUID? {
+ toState.checkValidState()
if (fromState != internalTransitionInteractor.currentTransitionInfoInternal.value.to) {
Log.e(
name,
@@ -166,6 +168,8 @@ sealed class TransitionInteractor(
*/
@Deprecated("Will be merged into maybeStartTransitionToOccludedOrInsecureCamera")
suspend fun maybeHandleInsecurePowerGesture(): Boolean {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return true
if (keyguardOcclusionInteractor.shouldTransitionFromPowerButtonGesture()) {
if (keyguardInteractor.isKeyguardDismissible.value) {
startTransitionTo(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index 1c7b4d996b36..76f7749754a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -38,7 +38,9 @@ import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.util.kotlin.DisposableHandles
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
@@ -64,8 +66,9 @@ object DeviceEntryIconViewBinder {
falsingManager: FalsingManager,
vibratorHelper: VibratorHelper,
overrideColor: Color? = null,
- ) {
+ ): DisposableHandle {
DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()
+ val disposables = DisposableHandles()
val longPressHandlingView = view.longPressHandlingView
val fgIconView = view.iconView
val bgView = view.bgView
@@ -83,118 +86,125 @@ object DeviceEntryIconViewBinder {
}
}
- view.repeatWhenAttached {
- // Repeat on CREATED so that the view will always observe the entire
- // GONE => AOD transition (even though the view may not be visible until the middle
- // of the transition.
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch("$TAG#viewModel.isVisible") {
- viewModel.isVisible.collect { isVisible ->
- longPressHandlingView.isInvisible = !isVisible
+ disposables +=
+ view.repeatWhenAttached {
+ // Repeat on CREATED so that the view will always observe the entire
+ // GONE => AOD transition (even though the view may not be visible until the middle
+ // of the transition.
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ launch("$TAG#viewModel.isVisible") {
+ viewModel.isVisible.collect { isVisible ->
+ longPressHandlingView.isInvisible = !isVisible
+ }
}
- }
- launch("$TAG#viewModel.isLongPressEnabled") {
- viewModel.isLongPressEnabled.collect { isEnabled ->
- longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
+ launch("$TAG#viewModel.isLongPressEnabled") {
+ viewModel.isLongPressEnabled.collect { isEnabled ->
+ longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
+ }
}
- }
- launch("$TAG#viewModel.isUdfpsSupported") {
- viewModel.isUdfpsSupported.collect { udfpsSupported ->
- longPressHandlingView.longPressDuration =
- if (udfpsSupported) {
- {
- view.resources
- .getInteger(R.integer.config_udfpsDeviceEntryIconLongPress)
- .toLong()
+ launch("$TAG#viewModel.isUdfpsSupported") {
+ viewModel.isUdfpsSupported.collect { udfpsSupported ->
+ longPressHandlingView.longPressDuration =
+ if (udfpsSupported) {
+ {
+ view.resources
+ .getInteger(
+ R.integer.config_udfpsDeviceEntryIconLongPress
+ )
+ .toLong()
+ }
+ } else {
+ {
+ view.resources
+ .getInteger(R.integer.config_lockIconLongPress)
+ .toLong()
+ }
}
- } else {
- {
- view.resources
- .getInteger(R.integer.config_lockIconLongPress)
- .toLong()
+ }
+ }
+ launch("$TAG#viewModel.accessibilityDelegateHint") {
+ viewModel.accessibilityDelegateHint.collect { hint ->
+ view.accessibilityHintType = hint
+ if (hint != DeviceEntryIconView.AccessibilityHintType.NONE) {
+ view.setOnClickListener {
+ vibratorHelper.performHapticFeedback(
+ view,
+ HapticFeedbackConstants.CONFIRM,
+ )
+ applicationScope.launch { viewModel.onUserInteraction() }
}
+ } else {
+ view.setOnClickListener(null)
}
+ }
}
- }
- launch("$TAG#viewModel.accessibilityDelegateHint") {
- viewModel.accessibilityDelegateHint.collect { hint ->
- view.accessibilityHintType = hint
- if (hint != DeviceEntryIconView.AccessibilityHintType.NONE) {
- view.setOnClickListener {
- vibratorHelper.performHapticFeedback(
- view,
- HapticFeedbackConstants.CONFIRM,
- )
- applicationScope.launch { viewModel.onUserInteraction() }
+ launch("$TAG#viewModel.useBackgroundProtection") {
+ viewModel.useBackgroundProtection.collect { useBackgroundProtection ->
+ if (useBackgroundProtection) {
+ bgView.visibility = View.VISIBLE
+ } else {
+ bgView.visibility = View.GONE
}
- } else {
- view.setOnClickListener(null)
}
}
- }
- launch("$TAG#viewModel.useBackgroundProtection") {
- viewModel.useBackgroundProtection.collect { useBackgroundProtection ->
- if (useBackgroundProtection) {
- bgView.visibility = View.VISIBLE
- } else {
- bgView.visibility = View.GONE
+ launch("$TAG#viewModel.burnInOffsets") {
+ viewModel.burnInOffsets.collect { burnInOffsets ->
+ view.translationX = burnInOffsets.x.toFloat()
+ view.translationY = burnInOffsets.y.toFloat()
+ view.aodFpDrawable.progress = burnInOffsets.progress
}
}
- }
- launch("$TAG#viewModel.burnInOffsets") {
- viewModel.burnInOffsets.collect { burnInOffsets ->
- view.translationX = burnInOffsets.x.toFloat()
- view.translationY = burnInOffsets.y.toFloat()
- view.aodFpDrawable.progress = burnInOffsets.progress
- }
- }
- launch("$TAG#viewModel.deviceEntryViewAlpha") {
- viewModel.deviceEntryViewAlpha.collect { alpha -> view.alpha = alpha }
+ launch("$TAG#viewModel.deviceEntryViewAlpha") {
+ viewModel.deviceEntryViewAlpha.collect { alpha -> view.alpha = alpha }
+ }
}
}
- }
- fgIconView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- // Start with an empty state
- fgIconView.setImageState(StateSet.NOTHING, /* merge */ false)
- launch("$TAG#fpIconView.viewModel") {
- fgViewModel.viewModel.collect { viewModel ->
- fgIconView.setImageState(
- view.getIconState(viewModel.type, viewModel.useAodVariant),
- /* merge */ false
- )
- if (viewModel.type.contentDescriptionResId != -1) {
- fgIconView.contentDescription =
- fgIconView.resources.getString(
- viewModel.type.contentDescriptionResId
- )
+ disposables +=
+ fgIconView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ // Start with an empty state
+ fgIconView.setImageState(StateSet.NOTHING, /* merge */ false)
+ launch("$TAG#fpIconView.viewModel") {
+ fgViewModel.viewModel.collect { viewModel ->
+ fgIconView.setImageState(
+ view.getIconState(viewModel.type, viewModel.useAodVariant),
+ /* merge */ false
+ )
+ if (viewModel.type.contentDescriptionResId != -1) {
+ fgIconView.contentDescription =
+ fgIconView.resources.getString(
+ viewModel.type.contentDescriptionResId
+ )
+ }
+ fgIconView.imageTintList =
+ ColorStateList.valueOf(overrideColor?.toArgb() ?: viewModel.tint)
+ fgIconView.setPadding(
+ viewModel.padding,
+ viewModel.padding,
+ viewModel.padding,
+ viewModel.padding,
+ )
}
- fgIconView.imageTintList =
- ColorStateList.valueOf(overrideColor?.toArgb() ?: viewModel.tint)
- fgIconView.setPadding(
- viewModel.padding,
- viewModel.padding,
- viewModel.padding,
- viewModel.padding,
- )
}
}
}
- }
- bgView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch("$TAG#bgViewModel.alpha") {
- bgViewModel.alpha.collect { alpha -> bgView.alpha = alpha }
- }
- launch("$TAG#bgViewModel.color") {
- bgViewModel.color.collect { color ->
- bgView.imageTintList = ColorStateList.valueOf(color)
+ disposables +=
+ bgView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ launch("$TAG#bgViewModel.alpha") {
+ bgViewModel.alpha.collect { alpha -> bgView.alpha = alpha }
+ }
+ launch("$TAG#bgViewModel.color") {
+ bgViewModel.color.collect { color ->
+ bgView.imageTintList = ColorStateList.valueOf(color)
+ }
}
}
}
- }
+
+ return disposables
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
index e0633807db88..ba9f01862e8e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
@@ -37,7 +37,9 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.clocks.AodClockBurnInModel
import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.util.kotlin.DisposableHandles
import com.android.systemui.util.ui.value
+import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -56,85 +58,94 @@ object KeyguardClockViewBinder {
keyguardClockInteractor: KeyguardClockInteractor,
blueprintInteractor: KeyguardBlueprintInteractor,
rootViewModel: KeyguardRootViewModel,
- ) {
- keyguardRootView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- keyguardClockInteractor.clockEventController.registerListeners(keyguardRootView)
- }
- }
-
- keyguardRootView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch {
- if (!MigrateClocksToBlueprint.isEnabled) return@launch
- viewModel.currentClock.collect { currentClock ->
- cleanupClockViews(currentClock, keyguardRootView, viewModel.burnInLayer)
- addClockViews(currentClock, keyguardRootView)
- updateBurnInLayer(keyguardRootView, viewModel, viewModel.clockSize.value)
- applyConstraints(clockSection, keyguardRootView, true)
- }
+ ): DisposableHandle {
+ val disposables = DisposableHandles()
+ disposables +=
+ keyguardRootView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ keyguardClockInteractor.clockEventController.registerListeners(keyguardRootView)
}
+ }
- launch {
- if (!MigrateClocksToBlueprint.isEnabled) return@launch
- viewModel.clockSize.collect { clockSize ->
- updateBurnInLayer(keyguardRootView, viewModel, clockSize)
- blueprintInteractor.refreshBlueprint(Type.ClockSize)
+ disposables +=
+ keyguardRootView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ viewModel.currentClock.collect { currentClock ->
+ cleanupClockViews(currentClock, keyguardRootView, viewModel.burnInLayer)
+ addClockViews(currentClock, keyguardRootView)
+ updateBurnInLayer(
+ keyguardRootView,
+ viewModel,
+ viewModel.clockSize.value
+ )
+ applyConstraints(clockSection, keyguardRootView, true)
+ }
}
- }
- launch {
- if (!MigrateClocksToBlueprint.isEnabled) return@launch
- viewModel.clockShouldBeCentered.collect {
- viewModel.currentClock.value?.let {
- // TODO(b/301502635): remove "!it.config.useCustomClockScene" when
- // migrate clocks to blueprint is fully rolled out
- if (
- it.largeClock.config.hasCustomPositionUpdatedAnimation &&
- !it.config.useCustomClockScene
- ) {
- blueprintInteractor.refreshBlueprint(Type.DefaultClockStepping)
- } else {
- blueprintInteractor.refreshBlueprint(Type.DefaultTransition)
- }
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ viewModel.clockSize.collect { clockSize ->
+ updateBurnInLayer(keyguardRootView, viewModel, clockSize)
+ blueprintInteractor.refreshBlueprint(Type.ClockSize)
}
}
- }
- launch {
- if (!MigrateClocksToBlueprint.isEnabled) return@launch
- combine(
- viewModel.hasAodIcons,
- rootViewModel.isNotifIconContainerVisible.map { it.value }
- ) { hasIcon, isVisible ->
- hasIcon && isVisible
- }
- .distinctUntilChanged()
- .collect { _ ->
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ viewModel.clockShouldBeCentered.collect {
viewModel.currentClock.value?.let {
- if (it.config.useCustomClockScene) {
+ // TODO(b/301502635): remove "!it.config.useCustomClockScene" when
+ // migrate clocks to blueprint is fully rolled out
+ if (
+ it.largeClock.config.hasCustomPositionUpdatedAnimation &&
+ !it.config.useCustomClockScene
+ ) {
+ blueprintInteractor.refreshBlueprint(Type.DefaultClockStepping)
+ } else {
blueprintInteractor.refreshBlueprint(Type.DefaultTransition)
}
}
}
- }
+ }
+
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ combine(
+ viewModel.hasAodIcons,
+ rootViewModel.isNotifIconContainerVisible.map { it.value }
+ ) { hasIcon, isVisible ->
+ hasIcon && isVisible
+ }
+ .distinctUntilChanged()
+ .collect { _ ->
+ viewModel.currentClock.value?.let {
+ if (it.config.useCustomClockScene) {
+ blueprintInteractor.refreshBlueprint(Type.DefaultTransition)
+ }
+ }
+ }
+ }
- launch {
- if (!MigrateClocksToBlueprint.isEnabled) return@launch
- rootViewModel.burnInModel.collect { burnInModel ->
- viewModel.currentClock.value?.let {
- it.largeClock.layout.applyAodBurnIn(
- AodClockBurnInModel(
- translationX = burnInModel.translationX.toFloat(),
- translationY = burnInModel.translationY.toFloat(),
- scale = burnInModel.scale
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ rootViewModel.burnInModel.collect { burnInModel ->
+ viewModel.currentClock.value?.let {
+ it.largeClock.layout.applyAodBurnIn(
+ AodClockBurnInModel(
+ translationX = burnInModel.translationX.toFloat(),
+ translationY = burnInModel.translationY.toFloat(),
+ scale = burnInModel.scale
+ )
)
- )
+ }
}
}
}
}
- }
+
+ return disposables
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index fc92afe17eff..8f149fbe99de 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -267,6 +267,23 @@ object KeyguardRootViewBinder {
}
}
+ launch {
+ blueprintViewModel.currentTransition.collect { currentTransition ->
+ // When blueprint/clock transitions end (null), make sure NSSL is in
+ // the right place
+ if (currentTransition == null) {
+ childViews[nsslPlaceholderId]?.let { notificationListPlaceholder
+ ->
+ viewModel.onNotificationContainerBoundsChanged(
+ notificationListPlaceholder.top.toFloat(),
+ notificationListPlaceholder.bottom.toFloat(),
+ animate = true,
+ )
+ }
+ }
+ }
+ }
+
if (NotificationIconContainerRefactor.isEnabled) {
launch {
val iconsAppearTranslationPx =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
index 191056c5578a..8b74f5dc791d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
@@ -31,6 +31,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.shared.R as sharedR
+import kotlinx.coroutines.DisposableHandle
object KeyguardSmartspaceViewBinder {
@JvmStatic
@@ -39,8 +40,8 @@ object KeyguardSmartspaceViewBinder {
clockViewModel: KeyguardClockViewModel,
smartspaceViewModel: KeyguardSmartspaceViewModel,
blueprintInteractor: KeyguardBlueprintInteractor,
- ) {
- keyguardRootView.repeatWhenAttached {
+ ): DisposableHandle {
+ return keyguardRootView.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
launch("$TAG#clockViewModel.hasCustomWeatherDataDisplay") {
if (!MigrateClocksToBlueprint.isEnabled) return@launch
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index 0637bba9f1de..91e48b56b4f5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -48,6 +48,7 @@ import com.android.systemui.shared.R as sharedR
import com.android.systemui.util.ui.value
import dagger.Lazy
import javax.inject.Inject
+import kotlinx.coroutines.DisposableHandle
internal fun ConstraintSet.setVisibility(
views: Iterable<View>,
@@ -70,21 +71,24 @@ constructor(
val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
private val rootViewModel: KeyguardRootViewModel,
) : KeyguardSection() {
+ private var disposableHandle: DisposableHandle? = null
+
override fun addViews(constraintLayout: ConstraintLayout) {}
override fun bindData(constraintLayout: ConstraintLayout) {
if (!MigrateClocksToBlueprint.isEnabled) {
return
}
-
- KeyguardClockViewBinder.bind(
- this,
- constraintLayout,
- keyguardClockViewModel,
- clockInteractor,
- blueprintInteractor.get(),
- rootViewModel,
- )
+ disposableHandle?.dispose()
+ disposableHandle =
+ KeyguardClockViewBinder.bind(
+ this,
+ constraintLayout,
+ keyguardClockViewModel,
+ clockInteractor,
+ blueprintInteractor.get(),
+ rootViewModel,
+ )
}
override fun applyConstraints(constraintSet: ConstraintSet) {
@@ -97,7 +101,13 @@ constructor(
}
}
- override fun removeViews(constraintLayout: ConstraintLayout) {}
+ override fun removeViews(constraintLayout: ConstraintLayout) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
+ return
+ }
+
+ disposableHandle?.dispose()
+ }
private fun buildConstraints(
clock: ClockController,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index e01f0a152b37..51230dd0a47c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -49,6 +49,7 @@ import com.android.systemui.statusbar.VibratorHelper
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.ExperimentalCoroutinesApi
/** Includes the device entry icon. */
@@ -70,6 +71,7 @@ constructor(
private val vibratorHelper: Lazy<VibratorHelper>,
) : KeyguardSection() {
private val deviceEntryIconViewId = R.id.device_entry_icon_view
+ private var disposableHandle: DisposableHandle? = null
override fun addViews(constraintLayout: ConstraintLayout) {
if (
@@ -97,15 +99,17 @@ constructor(
override fun bindData(constraintLayout: ConstraintLayout) {
if (DeviceEntryUdfpsRefactor.isEnabled) {
constraintLayout.findViewById<DeviceEntryIconView?>(deviceEntryIconViewId)?.let {
- DeviceEntryIconViewBinder.bind(
- applicationScope,
- it,
- deviceEntryIconViewModel.get(),
- deviceEntryForegroundViewModel.get(),
- deviceEntryBackgroundViewModel.get(),
- falsingManager.get(),
- vibratorHelper.get(),
- )
+ disposableHandle?.dispose()
+ disposableHandle =
+ DeviceEntryIconViewBinder.bind(
+ applicationScope,
+ it,
+ deviceEntryIconViewModel.get(),
+ deviceEntryForegroundViewModel.get(),
+ deviceEntryBackgroundViewModel.get(),
+ falsingManager.get(),
+ vibratorHelper.get(),
+ )
}
} else {
constraintLayout.findViewById<LockIconView?>(R.id.lock_icon_view)?.let {
@@ -178,6 +182,7 @@ constructor(
override fun removeViews(constraintLayout: ConstraintLayout) {
if (DeviceEntryUdfpsRefactor.isEnabled) {
constraintLayout.removeView(deviceEntryIconViewId)
+ disposableHandle?.dispose()
} else {
constraintLayout.removeView(R.id.lock_icon_view)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
index 8a751f05e102..55fc71823685 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
@@ -37,6 +37,7 @@ import com.android.systemui.shared.R as sharedR
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import dagger.Lazy
import javax.inject.Inject
+import kotlinx.coroutines.DisposableHandle
@SysUISingleton
open class SmartspaceSection
@@ -56,6 +57,7 @@ constructor(
private var smartspaceVisibilityListener: OnGlobalLayoutListener? = null
private var pastVisibility: Int = -1
+ private var disposableHandle: DisposableHandle? = null
override fun onRebuildBegin() {
smartspaceController.suppressDisconnects = true
@@ -96,12 +98,14 @@ constructor(
override fun bindData(constraintLayout: ConstraintLayout) {
if (!MigrateClocksToBlueprint.isEnabled) return
if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return
- KeyguardSmartspaceViewBinder.bind(
- constraintLayout,
- keyguardClockViewModel,
- keyguardSmartspaceViewModel,
- blueprintInteractor.get(),
- )
+ disposableHandle?.dispose()
+ disposableHandle =
+ KeyguardSmartspaceViewBinder.bind(
+ constraintLayout,
+ keyguardClockViewModel,
+ keyguardSmartspaceViewModel,
+ blueprintInteractor.get(),
+ )
}
override fun applyConstraints(constraintSet: ConstraintSet) {
@@ -188,6 +192,8 @@ constructor(
}
smartspaceView?.viewTreeObserver?.removeOnGlobalLayoutListener(smartspaceVisibilityListener)
smartspaceVisibilityListener = null
+
+ disposableHandle?.dispose()
}
private fun updateVisibility(constraintSet: ConstraintSet) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
index c4383fc0857d..680f966708be 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.ui.viewmodel
import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.FlowTracing.traceEmissionCount
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -229,7 +230,7 @@ constructor(
)
}
.distinctUntilChanged()
- }
+ }.traceEmissionCount({"QuickAfforcances#button${position.toSlotId()}"})
}
private fun KeyguardQuickAffordanceModel.toViewModel(
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 988fe640de2d..18a04ec60d56 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -158,7 +158,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
}
if (mp != null) {
if (DEBUG) {
- Log.d(mTag, "mPlayer.pause+release piid:" + player.getPlayerIId());
+ Log.d(mTag, "mp.pause+release piid:" + mp.getPlayerIId());
}
mp.pause();
try {
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
index de490a58a498..311cbfb7e632 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
@@ -96,12 +96,27 @@ constructor(
logDebug { "lockScreenState:isConfigSelected=$isConfigSelected" }
logDebug { "lockScreenState:isDefaultNotesAppSet=$isDefaultNotesAppSet" }
+ val isCustomLockScreenShortcutEnabled =
+ context.resources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled)
+ val isShortcutSelectedOrDefaultEnabled =
+ if (isCustomLockScreenShortcutEnabled) {
+ isConfigSelected
+ } else {
+ isStylusEverUsed
+ }
+ logDebug {
+ "lockScreenState:isCustomLockScreenShortcutEnabled=" +
+ isCustomLockScreenShortcutEnabled
+ }
+ logDebug {
+ "lockScreenState:isShortcutSelectedOrDefaultEnabled=" +
+ isShortcutSelectedOrDefaultEnabled
+ }
if (
isEnabled &&
isUserUnlocked &&
isDefaultNotesAppSet &&
- isConfigSelected &&
- isStylusEverUsed
+ isShortcutSelectedOrDefaultEnabled
) {
val contentDescription = ContentDescription.Resource(pickerNameResourceId)
val icon = Icon.Resource(pickerIconResourceId, contentDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
index f62b24aa96a3..3dcaff3de35a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
@@ -21,6 +21,7 @@ import android.provider.DeviceConfig
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.NotificationClassificationFlag
import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
@@ -51,7 +52,8 @@ constructor(val proxy: DeviceConfigProxy, val context: Context) {
}
fun getNotificationBuckets(): IntArray {
- if (PriorityPeopleSection.isEnabled || NotificationMinimalismPrototype.V2.isEnabled) {
+ if (PriorityPeopleSection.isEnabled || NotificationMinimalismPrototype.V2.isEnabled
+ || NotificationClassificationFlag.isEnabled) {
// We don't need this list to be adaptive, it can be the superset of all features.
return PriorityBucket.getAllInOrder()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationClassificationFlag.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationClassificationFlag.kt
new file mode 100644
index 000000000000..139347c86d54
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationClassificationFlag.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.notification.collection
+
+import android.service.notification.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/**
+ * Helper for android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION
+ */
+@Suppress("NOTHING_TO_INLINE")
+object NotificationClassificationFlag {
+ const val FLAG_NAME = Flags.FLAG_NOTIFICATION_CLASSIFICATION
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Are sections sorted by time? */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.notificationClassification()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinator.kt
new file mode 100644
index 000000000000..244c5946c21e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinator.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.notification.collection.coordinator
+
+import android.app.NotificationChannel.NEWS_ID
+import android.app.NotificationChannel.PROMOTIONS_ID
+import android.app.NotificationChannel.RECS_ID
+import android.app.NotificationChannel.SOCIAL_MEDIA_ID
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
+import com.android.systemui.statusbar.notification.collection.render.NodeController
+import com.android.systemui.statusbar.notification.dagger.NewsHeader
+import com.android.systemui.statusbar.notification.dagger.PromoHeader
+import com.android.systemui.statusbar.notification.dagger.RecsHeader
+import com.android.systemui.statusbar.notification.dagger.SocialHeader
+import com.android.systemui.statusbar.notification.stack.BUCKET_NEWS
+import com.android.systemui.statusbar.notification.stack.BUCKET_PROMO
+import com.android.systemui.statusbar.notification.stack.BUCKET_RECS
+import com.android.systemui.statusbar.notification.stack.BUCKET_SOCIAL
+import javax.inject.Inject
+
+/**
+ * Coordinator for sections derived from NotificationAssistantService classification.
+ */
+@CoordinatorScope
+class BundleCoordinator @Inject constructor(
+ @NewsHeader private val newsHeaderController: NodeController,
+ @SocialHeader private val socialHeaderController: NodeController,
+ @RecsHeader private val recsHeaderController: NodeController,
+ @PromoHeader private val promoHeaderController: NodeController,
+) : Coordinator {
+
+ val newsSectioner =
+ object : NotifSectioner("News", BUCKET_NEWS) {
+ override fun isInSection(entry: ListEntry): Boolean {
+ return entry.representativeEntry?.channel?.id == NEWS_ID
+ }
+
+ override fun getHeaderNodeController(): NodeController? {
+ return newsHeaderController
+ }
+ }
+
+ val socialSectioner =
+ object : NotifSectioner("Social", BUCKET_SOCIAL) {
+ override fun isInSection(entry: ListEntry): Boolean {
+ return entry.representativeEntry?.channel?.id == SOCIAL_MEDIA_ID
+ }
+
+ override fun getHeaderNodeController(): NodeController? {
+ return socialHeaderController
+ }
+ }
+
+ val recsSectioner =
+ object : NotifSectioner("Recommendations", BUCKET_RECS) {
+ override fun isInSection(entry: ListEntry): Boolean {
+ return entry.representativeEntry?.channel?.id == RECS_ID
+ }
+
+ override fun getHeaderNodeController(): NodeController? {
+ return recsHeaderController
+ }
+ }
+
+ val promoSectioner =
+ object : NotifSectioner("Promotions", BUCKET_PROMO) {
+ override fun isInSection(entry: ListEntry): Boolean {
+ return entry.representativeEntry?.channel?.id == PROMOTIONS_ID
+ }
+
+ override fun getHeaderNodeController(): NodeController? {
+ return promoHeaderController
+ }
+ }
+
+ override fun attach(pipeline: NotifPipeline) {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index e41352254bac..e0389820aedf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -17,10 +17,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
-import com.android.systemui.statusbar.notification.collection.NotifPipeline
-import com.android.systemui.statusbar.notification.collection.PipelineDumpable
-import com.android.systemui.statusbar.notification.collection.PipelineDumper
-import com.android.systemui.statusbar.notification.collection.SortBySectionTimeFlag
+import com.android.systemui.statusbar.notification.collection.*
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
@@ -69,6 +66,7 @@ constructor(
dismissibilityCoordinator: DismissibilityCoordinator,
dreamCoordinator: DreamCoordinator,
statsLoggerCoordinator: NotificationStatsLoggerCoordinator,
+ bundleCoordinator: BundleCoordinator,
) : NotifCoordinators {
private val mCoreCoordinators: MutableList<CoreCoordinator> = ArrayList()
@@ -132,6 +130,12 @@ constructor(
mOrderedSections.add(conversationCoordinator.peopleSilentSectioner) // People Silent
}
mOrderedSections.add(rankingCoordinator.alertingSectioner) // Alerting
+ if (NotificationClassificationFlag.isEnabled) {
+ mOrderedSections.add(bundleCoordinator.newsSectioner);
+ mOrderedSections.add(bundleCoordinator.socialSectioner);
+ mOrderedSections.add(bundleCoordinator.recsSectioner);
+ mOrderedSections.add(bundleCoordinator.promoSectioner);
+ }
mOrderedSections.add(rankingCoordinator.silentSectioner) // Silent
mOrderedSections.add(rankingCoordinator.minimizedSectioner) // Minimized
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
index ca43591e0776..e661090011c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
@@ -80,6 +80,50 @@ object NotificationSectionHeadersModule {
.build()
@Provides
+ @NewsHeader
+ @SysUISingleton
+ @JvmStatic fun providesNewsHeaderSubcomponent(
+ builder: Provider<SectionHeaderControllerSubcomponent.Builder>
+ ) = builder.get()
+ .nodeLabel("news header")
+ .headerText(com.android.internal.R.string.news_notification_channel_label)
+ .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS)
+ .build()
+
+ @Provides
+ @SocialHeader
+ @SysUISingleton
+ @JvmStatic fun providesSocialHeaderSubcomponent(
+ builder: Provider<SectionHeaderControllerSubcomponent.Builder>
+ ) = builder.get()
+ .nodeLabel("social header")
+ .headerText(com.android.internal.R.string.social_notification_channel_label)
+ .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS)
+ .build()
+
+ @Provides
+ @RecsHeader
+ @SysUISingleton
+ @JvmStatic fun providesRecsHeaderSubcomponent(
+ builder: Provider<SectionHeaderControllerSubcomponent.Builder>
+ ) = builder.get()
+ .nodeLabel("recs header")
+ .headerText(com.android.internal.R.string.recs_notification_channel_label)
+ .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS)
+ .build()
+
+ @Provides
+ @PromoHeader
+ @SysUISingleton
+ @JvmStatic fun providesPromoHeaderSubcomponent(
+ builder: Provider<SectionHeaderControllerSubcomponent.Builder>
+ ) = builder.get()
+ .nodeLabel("promo header")
+ .headerText(com.android.internal.R.string.promotional_notification_channel_label)
+ .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS)
+ .build()
+
+ @Provides
@SilentHeader
@JvmStatic fun providesSilentHeaderNodeController(
@SilentHeader subcomponent: SectionHeaderControllerSubcomponent
@@ -126,6 +170,54 @@ object NotificationSectionHeadersModule {
@JvmStatic fun providesIncomingHeaderController(
@IncomingHeader subcomponent: SectionHeaderControllerSubcomponent
) = subcomponent.headerController
+
+ @Provides
+ @NewsHeader
+ @JvmStatic fun providesNewsHeaderNodeController(
+ @NewsHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.nodeController
+
+ @Provides
+ @NewsHeader
+ @JvmStatic fun providesNewsHeaderController(
+ @NewsHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.headerController
+
+ @Provides
+ @SocialHeader
+ @JvmStatic fun providesSocialHeaderNodeController(
+ @SocialHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.nodeController
+
+ @Provides
+ @SocialHeader
+ @JvmStatic fun providesSocialHeaderController(
+ @SocialHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.headerController
+
+ @Provides
+ @RecsHeader
+ @JvmStatic fun providesRecsHeaderNodeController(
+ @RecsHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.nodeController
+
+ @Provides
+ @RecsHeader
+ @JvmStatic fun providesRecsHeaderController(
+ @RecsHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.headerController
+
+ @Provides
+ @PromoHeader
+ @JvmStatic fun providesPromoHeaderNodeController(
+ @PromoHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.nodeController
+
+ @Provides
+ @PromoHeader
+ @JvmStatic fun providesPromoHeaderController(
+ @PromoHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.headerController
}
@Subcomponent(modules = [ SectionHeaderBindingModule::class ])
@@ -183,3 +275,19 @@ annotation class HeaderClickAction
@Scope
@Retention(AnnotationRetention.BINARY)
annotation class SectionHeaderScope
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class NewsHeader
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class SocialHeader
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class RecsHeader
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class PromoHeader \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
index 9e0dd8fc4d92..175512336b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -20,9 +20,13 @@ import static com.android.systemui.statusbar.notification.stack.NotificationPrio
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_NEWS;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PRIORITY_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PROMO;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_RECS;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SOCIAL;
import android.annotation.Nullable;
import android.service.notification.StatusBarNotification;
@@ -135,6 +139,10 @@ public interface NotificationPanelLogger {
return Notifications.Notification.SECTION_PEOPLE;
case BUCKET_ALERTING: return Notifications.Notification.SECTION_ALERTING;
case BUCKET_SILENT: return Notifications.Notification.SECTION_SILENT;
+ case BUCKET_NEWS: return Notifications.Notification.SECTION_NEWS;
+ case BUCKET_SOCIAL: return Notifications.Notification.SECTION_SOCIAL;
+ case BUCKET_RECS: return Notifications.Notification.SECTION_RECS;
+ case BUCKET_PROMO: return Notifications.Notification.SECTION_PROMO;
}
return Notifications.Notification.SECTION_UNKNOWN;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
index c2ab2758dd74..ce4356ae6c2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
@@ -43,6 +43,13 @@ message Notification {
SECTION_ALERTING = 4;
SECTION_SILENT = 5;
SECTION_FOREGROUND_SERVICE = 6;
+ SECTION_PRIORITY_PEOPLE = 7;
+ SECTION_TOP_ONGOING = 8;
+ SECTION_TOP_UNSEEN = 9;
+ SECTION_NEWS = 10;
+ SECTION_SOCIAL = 11;
+ SECTION_RECS = 12;
+ SECTION_PROMO = 13;
}
optional NotificationSection section = 6;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
index fabb696d9182..f4a452784267 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
@@ -20,6 +20,10 @@ import android.annotation.IntDef
BUCKET_PRIORITY_PEOPLE,
BUCKET_PEOPLE,
BUCKET_ALERTING,
+ BUCKET_NEWS,
+ BUCKET_SOCIAL,
+ BUCKET_RECS,
+ BUCKET_PROMO,
BUCKET_SILENT
]
)
@@ -35,6 +39,10 @@ annotation class PriorityBucket {
BUCKET_PRIORITY_PEOPLE,
BUCKET_PEOPLE,
BUCKET_ALERTING,
+ BUCKET_NEWS,
+ BUCKET_SOCIAL,
+ BUCKET_RECS,
+ BUCKET_PROMO,
BUCKET_SILENT,
)
}
@@ -49,4 +57,9 @@ const val BUCKET_FOREGROUND_SERVICE = 3
const val BUCKET_PRIORITY_PEOPLE = 7
const val BUCKET_PEOPLE = 4
const val BUCKET_ALERTING = 5
+const val BUCKET_NEWS = 10
+const val BUCKET_SOCIAL = 11
+const val BUCKET_RECS = 12
+const val BUCKET_PROMO = 13
const val BUCKET_SILENT = 6
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 3400ad107133..7441c7058d7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -22,12 +22,10 @@ import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.media.controls.ui.controller.KeyguardMediaController
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.SourceType
+import com.android.systemui.statusbar.notification.collection.NotificationClassificationFlag
import com.android.systemui.statusbar.notification.collection.render.MediaContainerController
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController
-import com.android.systemui.statusbar.notification.dagger.AlertingHeader
-import com.android.systemui.statusbar.notification.dagger.IncomingHeader
-import com.android.systemui.statusbar.notification.dagger.PeopleHeader
-import com.android.systemui.statusbar.notification.dagger.SilentHeader
+import com.android.systemui.statusbar.notification.dagger.*
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
@@ -51,7 +49,11 @@ internal constructor(
@IncomingHeader private val incomingHeaderController: SectionHeaderController,
@PeopleHeader private val peopleHeaderController: SectionHeaderController,
@AlertingHeader private val alertingHeaderController: SectionHeaderController,
- @SilentHeader private val silentHeaderController: SectionHeaderController
+ @SilentHeader private val silentHeaderController: SectionHeaderController,
+ @NewsHeader private val newsHeaderController: SectionHeaderController,
+ @SocialHeader private val socialHeaderController: SectionHeaderController,
+ @RecsHeader private val recsHeaderController: SectionHeaderController,
+ @PromoHeader private val promoHeaderController: SectionHeaderController
) : SectionProvider {
private val configurationListener =
@@ -84,6 +86,22 @@ internal constructor(
val mediaControlsView: MediaContainerView?
get() = mediaContainerController.mediaContainerView
+ @VisibleForTesting
+ val newsHeaderView: SectionHeaderView?
+ get() = newsHeaderController.headerView
+
+ @VisibleForTesting
+ val socialHeaderView: SectionHeaderView?
+ get() = socialHeaderController.headerView
+
+ @VisibleForTesting
+ val recsHeaderView: SectionHeaderView?
+ get() = recsHeaderController.headerView
+
+ @VisibleForTesting
+ val promoHeaderView: SectionHeaderView?
+ get() = promoHeaderController.headerView
+
/** Must be called before use. */
fun initialize(parent: NotificationStackScrollLayout) {
check(!initialized) { "NotificationSectionsManager already initialized" }
@@ -107,15 +125,24 @@ internal constructor(
incomingHeaderController.reinflateView(parent)
mediaContainerController.reinflateView(parent)
keyguardMediaController.attachSinglePaneContainer(mediaControlsView)
+ if (NotificationClassificationFlag.isEnabled) {
+ newsHeaderController.reinflateView(parent)
+ socialHeaderController.reinflateView(parent)
+ recsHeaderController.reinflateView(parent)
+ promoHeaderController.reinflateView(parent)
+ }
}
override fun beginsSection(view: View, previous: View?): Boolean =
view === silentHeaderView ||
- view === mediaControlsView ||
- view === peopleHeaderView ||
- view === alertingHeaderView ||
- view === incomingHeaderView ||
- getBucket(view) != getBucket(previous)
+ view === mediaControlsView ||
+ view === peopleHeaderView ||
+ view === alertingHeaderView ||
+ view === incomingHeaderView ||
+ (NotificationClassificationFlag.isEnabled && (view === newsHeaderView
+ || view === socialHeaderView || view === recsHeaderView
+ || view === promoHeaderView)) ||
+ getBucket(view) != getBucket(previous)
private fun getBucket(view: View?): Int? =
when {
@@ -124,6 +151,10 @@ internal constructor(
view === mediaControlsView -> BUCKET_MEDIA_CONTROLS
view === peopleHeaderView -> BUCKET_PEOPLE
view === alertingHeaderView -> BUCKET_ALERTING
+ view === newsHeaderView -> BUCKET_NEWS
+ view === socialHeaderView -> BUCKET_SOCIAL
+ view === recsHeaderView -> BUCKET_RECS
+ view === promoHeaderView -> BUCKET_PROMO
view is ExpandableNotificationRow -> view.entry.bucket
else -> null
}
@@ -255,6 +286,12 @@ internal constructor(
peopleHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
silentHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
alertingHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ if (NotificationClassificationFlag.isEnabled) {
+ newsHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ socialHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ recsHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ promoHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 4ce901030e57..0623bb2c274a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -107,7 +107,6 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
private int mStatusBarState;
private AnimationStateHandler mAnimationStateHandler;
- private Handler mBgHandler;
private int mHeadsUpInset;
// Used for determining the region for touch interaction
@@ -152,8 +151,7 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
UiEventLogger uiEventLogger,
JavaAdapter javaAdapter,
ShadeInteractor shadeInteractor,
- AvalancheController avalancheController,
- @Background Handler bgHandler) {
+ AvalancheController avalancheController) {
super(context, logger, handler, globalSettings, systemClock, executor,
accessibilityManagerWrapper, uiEventLogger, avalancheController);
Resources resources = mContext.getResources();
@@ -163,7 +161,6 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
mGroupMembershipManager = groupMembershipManager;
mVisualStabilityProvider = visualStabilityProvider;
mAvalancheController = avalancheController;
- mBgHandler = bgHandler;
updateResources();
configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
@Override
@@ -405,11 +402,8 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
// Waiting HUNs in AvalancheController are still promoted to the HUN section and thus
// seen in open shade; clear them so we don't show them again when the shade closes and
// reordering is allowed again.
- int waitingKeysSize = mAvalancheController.getWaitingKeys().size();
- mBgHandler.post(() -> {
- // Do this in the background to avoid missing frames when closing the shade
- mAvalancheController.logDroppedHuns(waitingKeysSize);
- });
+ final int numDropped = mAvalancheController.getWaitingKeys().size();
+ mAvalancheController.logDroppedHunsInBackground(numDropped);
mAvalancheController.clearNext();
// In open shade the first HUN is pinned, and visual stability logic prevents us from
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 dbe54f346072..8aabdf2a40f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -15,12 +15,14 @@
*/
package com.android.systemui.statusbar.policy
+import android.os.Handler
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
import com.android.systemui.statusbar.policy.BaseHeadsUpManager.HeadsUpEntry
@@ -35,7 +37,10 @@ import javax.inject.Inject
@SysUISingleton
class AvalancheController
@Inject
-constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger) : Dumpable {
+constructor(dumpManager: DumpManager,
+ private val uiEventLogger: UiEventLogger,
+ @Background private val bgHandler: Handler
+) : Dumpable {
private val tag = "AvalancheController"
private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG)
@@ -315,7 +320,7 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)
// Remove runnable labels for dropped huns
val listToDrop = nextList.subList(1, nextList.size)
- logDroppedHuns(listToDrop.size)
+ logDroppedHunsInBackground(listToDrop.size)
if (debug) {
// Clear runnable labels
@@ -332,10 +337,13 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)
showNow(headsUpEntryShowing!!, headsUpEntryShowingRunnableList)
}
- fun logDroppedHuns(numDropped: Int) {
- for (n in 1..numDropped) {
- uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_DROPPED)
- }
+ fun logDroppedHunsInBackground(numDropped: Int) {
+ bgHandler.post(Runnable {
+ // Do this in the background to avoid missing frames when closing the shade
+ for (n in 1..numDropped) {
+ uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_DROPPED)
+ }
+ })
}
fun clearNext() {
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java b/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java
new file mode 100644
index 000000000000..e13981dfe5c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java
@@ -0,0 +1,34 @@
+/*
+ * 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.util.kotlin;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/**
+ * This is a background executor/dispatcher which guarantees that **within that instance**,
+ * operations will execute in the same order as they were dispatched.
+ * This is useful for background operations like register/unregister where ordering is important.
+ */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface SettingsSingleThreadBackground { }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
index b836016eb2ef..a03221e03467 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -16,6 +16,7 @@
package com.android.systemui.util.kotlin
+import android.os.Handler
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -23,15 +24,16 @@ import com.android.systemui.dagger.qualifiers.Tracing
import com.android.systemui.dagger.qualifiers.UiBackground
import dagger.Module
import dagger.Provides
-import java.util.concurrent.Executor
-import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.android.asCoroutineDispatcher
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.newFixedThreadPoolContext
import kotlinx.coroutines.plus
+import java.util.concurrent.Executor
+import kotlin.coroutines.CoroutineContext
private const val LIMIT_BACKGROUND_DISPATCHER_THREADS = true
@@ -78,6 +80,14 @@ class SysUICoroutinesModule {
}
@Provides
+ @SysUISingleton
+ @SettingsSingleThreadBackground
+ fun settingsBgDispatcher(@Background bgHandler: Handler): CoroutineDispatcher {
+ // Handlers are guaranteed to be sequential so we use that one for now.
+ return bgHandler.asCoroutineDispatcher("SettingsBg")
+ }
+
+ @Provides
@Background
@SysUISingleton
fun bgCoroutineContext(
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
index 4438763aa765..816f55db65a0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
@@ -23,7 +23,7 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.provider.Settings;
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
import kotlinx.coroutines.CoroutineDispatcher;
@@ -37,7 +37,7 @@ class GlobalSettingsImpl implements GlobalSettings {
@Inject
GlobalSettingsImpl(ContentResolver contentResolver,
- @Background CoroutineDispatcher bgDispatcher) {
+ @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
mContentResolver = contentResolver;
mBgDispatcher = bgDispatcher;
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
index 38ad5d0d0cab..9c98f43e2501 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
@@ -22,13 +22,13 @@ import android.provider.Settings;
import androidx.annotation.NonNull;
-import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.settings.UserTracker;
-
-import kotlinx.coroutines.CoroutineDispatcher;
+import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
import javax.inject.Inject;
+import kotlinx.coroutines.CoroutineDispatcher;
+
class SecureSettingsImpl implements SecureSettings {
private final ContentResolver mContentResolver;
private final UserTracker mUserTracker;
@@ -36,7 +36,7 @@ class SecureSettingsImpl implements SecureSettings {
@Inject
SecureSettingsImpl(ContentResolver contentResolver, UserTracker userTracker,
- @Background CoroutineDispatcher bgDispatcher) {
+ @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
mContentResolver = contentResolver;
mUserTracker = userTracker;
mBgDispatcher = bgDispatcher;
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
index 68cc753bc48a..406d95bd8fd1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
@@ -22,13 +22,13 @@ import android.provider.Settings;
import androidx.annotation.NonNull;
-import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.settings.UserTracker;
-
-import kotlinx.coroutines.CoroutineDispatcher;
+import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
import javax.inject.Inject;
+import kotlinx.coroutines.CoroutineDispatcher;
+
class SystemSettingsImpl implements SystemSettings {
private final ContentResolver mContentResolver;
private final UserTracker mUserTracker;
@@ -36,7 +36,7 @@ class SystemSettingsImpl implements SystemSettings {
@Inject
SystemSettingsImpl(ContentResolver contentResolver, UserTracker userTracker,
- @Background CoroutineDispatcher bgDispatcher) {
+ @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
mContentResolver = contentResolver;
mUserTracker = userTracker;
mBgCoroutineDispatcher = bgDispatcher;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 9a99ed7bb512..1e3ee280204b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -27,6 +27,7 @@ import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.PromptVerticalListContentView
import android.hardware.face.FaceSensorPropertiesInternal
+import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.os.Handler
import android.os.IBinder
@@ -88,9 +89,8 @@ import org.mockito.Mockito.eq
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
-
+import org.mockito.junit.MockitoJUnit
private const val OP_PACKAGE_NAME = "biometric.testapp"
@@ -99,33 +99,21 @@ private const val OP_PACKAGE_NAME = "biometric.testapp"
@SmallTest
open class AuthContainerViewTest : SysuiTestCase() {
- @JvmField @Rule
- var mockitoRule = MockitoJUnit.rule()
-
- @Mock
- lateinit var callback: AuthDialogCallback
- @Mock
- lateinit var userManager: UserManager
- @Mock
- lateinit var lockPatternUtils: LockPatternUtils
- @Mock
- lateinit var wakefulnessLifecycle: WakefulnessLifecycle
- @Mock
- lateinit var panelInteractionDetector: AuthDialogPanelInteractionDetector
- @Mock
- lateinit var windowToken: IBinder
- @Mock
- lateinit var interactionJankMonitor: InteractionJankMonitor
- @Mock
- lateinit var vibrator: VibratorHelper
- @Mock
- lateinit var udfpsUtils: UdfpsUtils
- @Mock
- lateinit var authController: AuthController
- @Mock
- lateinit var selectedUserInteractor: SelectedUserInteractor
- @Mock
- private lateinit var packageManager: PackageManager
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ @Mock lateinit var callback: AuthDialogCallback
+ @Mock lateinit var userManager: UserManager
+ @Mock lateinit var fingerprintManager: FingerprintManager
+ @Mock lateinit var lockPatternUtils: LockPatternUtils
+ @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle
+ @Mock lateinit var panelInteractionDetector: AuthDialogPanelInteractionDetector
+ @Mock lateinit var windowToken: IBinder
+ @Mock lateinit var interactionJankMonitor: InteractionJankMonitor
+ @Mock lateinit var vibrator: VibratorHelper
+ @Mock lateinit var udfpsUtils: UdfpsUtils
+ @Mock lateinit var authController: AuthController
+ @Mock lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var packageManager: PackageManager
@Mock private lateinit var activityTaskManager: ActivityTaskManager
private lateinit var displayRepository: FakeDisplayRepository
@@ -141,11 +129,12 @@ open class AuthContainerViewTest : SysuiTestCase() {
private val fingerprintRepository = FakeFingerprintPropertyRepository()
private val displayStateRepository = FakeDisplayStateRepository()
private val credentialInteractor = FakeCredentialInteractor()
- private val bpCredentialInteractor = PromptCredentialInteractor(
- Dispatchers.Main.immediate,
- biometricPromptRepository,
- credentialInteractor,
- )
+ private val bpCredentialInteractor =
+ PromptCredentialInteractor(
+ Dispatchers.Main.immediate,
+ biometricPromptRepository,
+ credentialInteractor,
+ )
private val promptSelectorInteractor by lazy {
PromptSelectorInteractorImpl(
fingerprintRepository,
@@ -166,22 +155,26 @@ open class AuthContainerViewTest : SysuiTestCase() {
displayStateInteractor =
DisplayStateInteractorImpl(
- testScope.backgroundScope,
- mContext,
- fakeExecutor,
- displayStateRepository,
- displayRepository,
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ displayStateRepository,
+ displayRepository,
)
udfpsOverlayInteractor =
- UdfpsOverlayInteractor(
- context,
- authController,
- selectedUserInteractor,
- testScope.backgroundScope,
- )
+ UdfpsOverlayInteractor(
+ context,
+ authController,
+ selectedUserInteractor,
+ fingerprintManager,
+ testScope.backgroundScope,
+ )
biometricStatusInteractor =
- BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository,
- fingerprintRepository)
+ BiometricStatusInteractorImpl(
+ activityTaskManager,
+ biometricStatusRepository,
+ fingerprintRepository
+ )
iconProvider = IconProvider(context)
// Set up default logo icon
whenever(packageManager.getApplicationIcon(OP_PACKAGE_NAME)).thenReturn(defaultLogoIcon)
@@ -198,10 +191,8 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testNotifiesAnimatedIn() {
initializeFingerprintContainer()
- verify(callback).onDialogAnimatedIn(
- authContainer?.requestId ?: 0L,
- true /* startFingerprintNow */
- )
+ verify(callback)
+ .onDialogAnimatedIn(authContainer?.requestId ?: 0L, true /* startFingerprintNow */)
}
@Test
@@ -246,10 +237,8 @@ open class AuthContainerViewTest : SysuiTestCase() {
waitForIdleSync()
// attaching the view resets the state and allows this to happen again
- verify(callback).onDialogAnimatedIn(
- authContainer?.requestId ?: 0L,
- true /* startFingerprintNow */
- )
+ verify(callback)
+ .onDialogAnimatedIn(authContainer?.requestId ?: 0L, true /* startFingerprintNow */)
}
@Test
@@ -274,10 +263,8 @@ open class AuthContainerViewTest : SysuiTestCase() {
// the first time is triggered by initializeFingerprintContainer()
// the second time was triggered by dismissWithoutCallback()
- verify(callback, times(2)).onDialogAnimatedIn(
- authContainer?.requestId ?: 0L,
- true /* startFingerprintNow */
- )
+ verify(callback, times(2))
+ .onDialogAnimatedIn(authContainer?.requestId ?: 0L, true /* startFingerprintNow */)
}
@Test
@@ -288,18 +275,18 @@ open class AuthContainerViewTest : SysuiTestCase() {
verify(panelInteractionDetector).disable()
}
-
@Test
fun testActionAuthenticated_sendsDismissedAuthenticated() {
val container = initializeFingerprintContainer()
container.mBiometricCallback.onAuthenticated()
waitForIdleSync()
- verify(callback).onDismissed(
+ verify(callback)
+ .onDismissed(
eq(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L)
- )
+ )
assertThat(container.parent).isNull()
}
@@ -309,15 +296,17 @@ open class AuthContainerViewTest : SysuiTestCase() {
container.mBiometricCallback.onUserCanceled()
waitForIdleSync()
- verify(callback).onSystemEvent(
+ verify(callback)
+ .onSystemEvent(
eq(BiometricConstants.BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL),
eq(authContainer?.requestId ?: 0L)
- )
- verify(callback).onDismissed(
+ )
+ verify(callback)
+ .onDismissed(
eq(AuthDialogCallback.DISMISSED_USER_CANCELED),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L)
- )
+ )
assertThat(container.parent).isNull()
}
@@ -327,19 +316,21 @@ open class AuthContainerViewTest : SysuiTestCase() {
container.mBiometricCallback.onButtonNegative()
waitForIdleSync()
- verify(callback).onDismissed(
+ verify(callback)
+ .onDismissed(
eq(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L)
- )
+ )
assertThat(container.parent).isNull()
}
@Test
fun testActionTryAgain_sendsTryAgain() {
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
+ )
container.mBiometricCallback.onButtonTryAgain()
waitForIdleSync()
@@ -352,21 +343,24 @@ open class AuthContainerViewTest : SysuiTestCase() {
container.mBiometricCallback.onError()
waitForIdleSync()
- verify(callback).onDismissed(
+ verify(callback)
+ .onDismissed(
eq(AuthDialogCallback.DISMISSED_ERROR),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L)
- )
+ )
assertThat(authContainer!!.parent).isNull()
}
@Ignore("b/279650412")
@Test
fun testActionUseDeviceCredential_sendsOnDeviceCredentialPressed() {
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
- BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators =
+ BiometricManager.Authenticators.BIOMETRIC_WEAK or
+ BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
container.mBiometricCallback.onUseDeviceCredential()
waitForIdleSync()
@@ -376,10 +370,12 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testAnimateToCredentialUI_invokesStartTransitionToCredentialUI() {
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
- BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators =
+ BiometricManager.Authenticators.BIOMETRIC_WEAK or
+ BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
container.animateToCredentialUI(false)
waitForIdleSync()
@@ -395,10 +391,12 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testAnimateToCredentialUI_rotateCredentialUI() {
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
- BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators =
+ BiometricManager.Authenticators.BIOMETRIC_WEAK or
+ BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
container.animateToCredentialUI(false)
waitForIdleSync()
@@ -437,13 +435,12 @@ open class AuthContainerViewTest : SysuiTestCase() {
mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
var isButtonClicked = false
val contentView =
- PromptContentViewWithMoreOptionsButton.Builder()
- .setMoreOptionsButtonListener(
- fakeExecutor) { _, _ -> isButtonClicked = true }
- .build()
+ PromptContentViewWithMoreOptionsButton.Builder()
+ .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> isButtonClicked = true }
+ .build()
val container =
- initializeFingerprintContainer(contentViewWithMoreOptionsButton = contentView)
+ initializeFingerprintContainer(contentViewWithMoreOptionsButton = contentView)
waitForIdleSync()
@@ -461,9 +458,9 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testShowCredentialUI_withDescription() {
val container =
- initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
waitForIdleSync()
assertThat(container.hasCredentialView()).isTrue()
@@ -475,10 +472,10 @@ open class AuthContainerViewTest : SysuiTestCase() {
mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP)
mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
val container =
- initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
- verticalListContentView = PromptVerticalListContentView.Builder().build()
- )
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
+ verticalListContentView = PromptVerticalListContentView.Builder().build()
+ )
// Two-step credential view should show -
// 1. biometric prompt without sensor 2. credential view ui
waitForIdleSync()
@@ -497,14 +494,14 @@ open class AuthContainerViewTest : SysuiTestCase() {
mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP)
mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
val contentView =
- PromptContentViewWithMoreOptionsButton.Builder()
- .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> }
- .build()
+ PromptContentViewWithMoreOptionsButton.Builder()
+ .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> }
+ .build()
val container =
- initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
- contentViewWithMoreOptionsButton = contentView
- )
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
+ contentViewWithMoreOptionsButton = contentView
+ )
waitForIdleSync()
assertThat(container.hasCredentialView()).isTrue()
@@ -514,13 +511,13 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testCredentialViewUsesEffectiveUserId() {
whenever(userManager.getCredentialOwnerProfile(anyInt())).thenReturn(200)
- whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(200))).thenReturn(
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
- )
+ whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(200)))
+ .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
waitForIdleSync()
assertThat(container.hasCredentialPatternView()).isTrue()
@@ -531,9 +528,8 @@ open class AuthContainerViewTest : SysuiTestCase() {
fun testCredentialUI_disablesClickingOnBackground() {
val container = initializeCredentialPasswordContainer()
assertThat(container.hasBiometricPrompt()).isFalse()
- assertThat(
- container.findViewById<View>(R.id.background)?.isImportantForAccessibility
- ).isFalse()
+ assertThat(container.findViewById<View>(R.id.background)?.isImportantForAccessibility)
+ .isFalse()
container.findViewById<View>(R.id.background)?.performClick()
waitForIdleSync()
@@ -552,7 +548,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
fun testLayoutParams_hasShowWhenLockedFlag() {
val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
assertThat((layoutParams.flags and WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) != 0)
- .isTrue()
+ .isTrue()
}
@Test
@@ -590,20 +586,20 @@ open class AuthContainerViewTest : SysuiTestCase() {
}
private fun initializeCredentialPasswordContainer(
- addToView: Boolean = true,
+ addToView: Boolean = true,
): TestAuthContainerView {
whenever(userManager.getCredentialOwnerProfile(anyInt())).thenReturn(20)
- whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(20))).thenReturn(
- DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
- )
+ whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(20)))
+ .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)
// In the credential view, clicking on the background (to cancel authentication) is not
// valid. Thus, the listener should be null, and it should not be in the accessibility
// hierarchy.
- val container = initializeFingerprintContainer(
+ val container =
+ initializeFingerprintContainer(
authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
addToView = addToView,
- )
+ )
waitForIdleSync()
assertThat(container.hasCredentialPasswordView()).isTrue()
@@ -615,26 +611,28 @@ open class AuthContainerViewTest : SysuiTestCase() {
addToView: Boolean = true,
verticalListContentView: PromptVerticalListContentView? = null,
contentViewWithMoreOptionsButton: PromptContentViewWithMoreOptionsButton? = null,
- ) = initializeContainer(
- TestAuthContainerView(
- authenticators = authenticators,
- fingerprintProps = fingerprintSensorPropertiesInternal(),
+ ) =
+ initializeContainer(
+ TestAuthContainerView(
+ authenticators = authenticators,
+ fingerprintProps = fingerprintSensorPropertiesInternal(),
verticalListContentView = verticalListContentView,
- ),
- addToView
- )
+ ),
+ addToView
+ )
private fun initializeCoexContainer(
authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
addToView: Boolean = true
- ) = initializeContainer(
- TestAuthContainerView(
- authenticators = authenticators,
- fingerprintProps = fingerprintSensorPropertiesInternal(),
- faceProps = faceSensorPropertiesInternal()
- ),
- addToView
- )
+ ) =
+ initializeContainer(
+ TestAuthContainerView(
+ authenticators = authenticators,
+ fingerprintProps = fingerprintSensorPropertiesInternal(),
+ faceProps = faceSensorPropertiesInternal()
+ ),
+ addToView
+ )
private fun initializeContainer(
view: TestAuthContainerView,
@@ -655,47 +653,50 @@ open class AuthContainerViewTest : SysuiTestCase() {
faceProps: List<FaceSensorPropertiesInternal> = listOf(),
verticalListContentView: PromptVerticalListContentView? = null,
contentViewWithMoreOptionsButton: PromptContentViewWithMoreOptionsButton? = null,
- ) : AuthContainerView(
- Config().apply {
- mContext = this@AuthContainerViewTest.context
- mCallback = callback
- mSensorIds = (fingerprintProps.map { it.sensorId } +
- faceProps.map { it.sensorId }).toIntArray()
- mSkipAnimation = true
- mPromptInfo = PromptInfo().apply {
- this.authenticators = authenticators
- if (verticalListContentView != null) {
- this.contentView = verticalListContentView
- } else if (contentViewWithMoreOptionsButton != null) {
- this.contentView = contentViewWithMoreOptionsButton
- }
- }
- mOpPackageName = OP_PACKAGE_NAME
- },
- testScope.backgroundScope,
- fingerprintProps,
- faceProps,
- wakefulnessLifecycle,
- panelInteractionDetector,
- userManager,
- lockPatternUtils,
- interactionJankMonitor,
- { promptSelectorInteractor },
- PromptViewModel(
- displayStateInteractor,
- promptSelectorInteractor,
- context,
- udfpsOverlayInteractor,
- biometricStatusInteractor,
- udfpsUtils,
- iconProvider,
- activityTaskManager
- ),
- { credentialViewModel },
- Handler(TestableLooper.get(this).looper),
- fakeExecutor,
- vibrator
- ) {
+ ) :
+ AuthContainerView(
+ Config().apply {
+ mContext = this@AuthContainerViewTest.context
+ mCallback = callback
+ mSensorIds =
+ (fingerprintProps.map { it.sensorId } + faceProps.map { it.sensorId })
+ .toIntArray()
+ mSkipAnimation = true
+ mPromptInfo =
+ PromptInfo().apply {
+ this.authenticators = authenticators
+ if (verticalListContentView != null) {
+ this.contentView = verticalListContentView
+ } else if (contentViewWithMoreOptionsButton != null) {
+ this.contentView = contentViewWithMoreOptionsButton
+ }
+ }
+ mOpPackageName = OP_PACKAGE_NAME
+ },
+ testScope.backgroundScope,
+ fingerprintProps,
+ faceProps,
+ wakefulnessLifecycle,
+ panelInteractionDetector,
+ userManager,
+ lockPatternUtils,
+ interactionJankMonitor,
+ { promptSelectorInteractor },
+ PromptViewModel(
+ displayStateInteractor,
+ promptSelectorInteractor,
+ context,
+ udfpsOverlayInteractor,
+ biometricStatusInteractor,
+ udfpsUtils,
+ iconProvider,
+ activityTaskManager
+ ),
+ { credentialViewModel },
+ Handler(TestableLooper.get(this).looper),
+ fakeExecutor,
+ vibrator
+ ) {
override fun postOnAnimation(runnable: Runnable) {
runnable.run()
}
@@ -717,8 +718,10 @@ open class AuthContainerViewTest : SysuiTestCase() {
val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
val lpFlags = layoutParams.flags
- assertThat((lpFlags and WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS)
- != 0).isTrue()
+ assertThat(
+ (lpFlags and WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) != 0
+ )
+ .isTrue()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
index 3d63c5b6d0f8..13f2c7212e36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.domain.interactor
import android.graphics.Rect
+import android.hardware.fingerprint.FingerprintManager
import android.view.MotionEvent
import android.view.Surface
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -51,6 +52,7 @@ class UdfpsOverlayInteractorTest : SysuiTestCase() {
private lateinit var testScope: TestScope
+ @Mock private lateinit var fingerprintManager: FingerprintManager
@Mock private lateinit var authController: AuthController
@Captor private lateinit var authControllerCallback: ArgumentCaptor<AuthController.Callback>
@@ -111,6 +113,7 @@ class UdfpsOverlayInteractorTest : SysuiTestCase() {
context,
authController,
selectedUserInteractor,
+ fingerprintManager,
testScope.backgroundScope
)
testScope.runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt
deleted file mode 100644
index b986c52309f8..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.keyboard.shortcut.data.repository
-
-import android.view.KeyEvent
-import android.view.KeyboardShortcutGroup
-import android.view.KeyboardShortcutInfo
-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.keyboard.shortcut.shared.model.Shortcut
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
-import com.android.systemui.keyboard.shortcut.shared.model.shortcutCategory
-import com.android.systemui.keyboard.shortcut.shortcutHelperCategoriesRepository
-import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
-import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.testKosmos
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class ShortcutHelperCategoriesRepositoryTest : SysuiTestCase() {
- @OptIn(ExperimentalCoroutinesApi::class)
- private val kosmos = testKosmos().also { it.testDispatcher = UnconfinedTestDispatcher() }
- private val repo = kosmos.shortcutHelperCategoriesRepository
- private val helper = kosmos.shortcutHelperTestHelper
- private val testScope = kosmos.testScope
-
- @Test
- fun stateActive_imeShortcuts_shortcutInfoCorrectlyConverted() =
- testScope.runTest {
- helper.setImeShortcuts(imeShortcutsGroupWithPreviousLanguageSwitchShortcut)
- val imeShortcutCategory by collectLastValue(repo.imeShortcutsCategory)
-
- helper.showFromActivity()
-
- assertThat(imeShortcutCategory)
- .isEqualTo(expectedImeShortcutCategoryWithPreviousLanguageSwitchShortcut)
- }
-
- @Test
- fun stateActive_imeShortcuts_onlyUnsupportedShortcuts_discardsAll() =
- testScope.runTest {
- helper.setImeShortcuts(imeShortcutsGroupWithUnsupportedShortcutModifiers)
- val imeShortcutCategory by collectLastValue(repo.imeShortcutsCategory)
-
- helper.showFromActivity()
-
- assertThat(imeShortcutCategory).isEqualTo(null)
- }
-
- private val switchToPreviousLanguageCommand =
- ShortcutCommand(
- listOf(KeyEvent.META_CTRL_ON, KeyEvent.META_SHIFT_ON, KeyEvent.KEYCODE_SPACE)
- )
-
- private val expectedImeShortcutCategoryWithDiscardedUnsupportedShortcuts =
- shortcutCategory(ShortcutCategoryType.IME) { subCategory("input", emptyList()) }
-
- private val switchToPreviousLanguageKeyboardShortcutInfo =
- KeyboardShortcutInfo(
- /* label = */ "switch to previous language",
- /* keycode = */ switchToPreviousLanguageCommand.keyCodes[2],
- /* modifiers = */ switchToPreviousLanguageCommand.keyCodes[0] or
- switchToPreviousLanguageCommand.keyCodes[1],
- )
-
- private val expectedImeShortcutCategoryWithPreviousLanguageSwitchShortcut =
- shortcutCategory(ShortcutCategoryType.IME) {
- subCategory(
- "input",
- listOf(
- Shortcut(
- switchToPreviousLanguageKeyboardShortcutInfo.label!!.toString(),
- listOf(switchToPreviousLanguageCommand)
- )
- )
- )
- }
-
- private val imeShortcutsGroupWithPreviousLanguageSwitchShortcut =
- listOf(
- KeyboardShortcutGroup(
- "input",
- listOf(
- switchToPreviousLanguageKeyboardShortcutInfo,
- )
- )
- )
-
- private val shortcutInfoWithUnsupportedModifier =
- KeyboardShortcutInfo(
- /* label = */ "unsupported shortcut",
- /* keycode = */ KeyEvent.KEYCODE_SPACE,
- /* modifiers = */ 32
- )
-
- private val imeShortcutsGroupWithUnsupportedShortcutModifiers =
- listOf(
- KeyboardShortcutGroup(
- "input",
- listOf(
- shortcutInfoWithUnsupportedModifier,
- )
- )
- )
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
index 3caa8f6cd138..0b4e6a289f0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
@@ -65,17 +65,6 @@ class ShortcutHelperStateRepositoryTest : SysuiTestCase() {
}
@Test
- fun state_activeThroughActivity_virtualKeyboardActive_emitsActiveWithVirtualDeviceId() =
- testScope.runTest {
- val state by collectLastValue(repo.state)
-
- fakeInputManager.addVirtualKeyboard()
- helper.showFromActivity()
-
- assertThat(state).isEqualTo(ShortcutHelperState.Active(VIRTUAL_KEYBOARD))
- }
-
- @Test
fun state_activeThroughActivity_physicalKeyboardActive_emitsActiveWithDeviceId() =
testScope.runTest {
val deviceId = 456
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
new file mode 100644
index 000000000000..c2814bd45e86
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -0,0 +1,235 @@
+/*
+ * 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.keyboard.shortcut.data.source
+
+import android.view.KeyEvent
+import android.view.KeyboardShortcutGroup
+import android.view.KeyboardShortcutInfo
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
+import com.android.systemui.keyboard.shortcut.shared.model.shortcut
+import com.android.systemui.res.R
+
+object TestShortcuts {
+
+ private val shortcutInfoWithRepeatedLabel =
+ KeyboardShortcutInfo(
+ /* label = */ "Shortcut with repeated label",
+ /* keycode = */ KeyEvent.KEYCODE_H,
+ /* modifiers = */ KeyEvent.META_META_ON,
+ )
+
+ private val shortcutInfoWithRepeatedLabelAlternate =
+ KeyboardShortcutInfo(
+ /* label = */ shortcutInfoWithRepeatedLabel.label,
+ /* keycode = */ KeyEvent.KEYCODE_L,
+ /* modifiers = */ KeyEvent.META_META_ON,
+ )
+
+ private val shortcutInfoWithRepeatedLabelSecondAlternate =
+ KeyboardShortcutInfo(
+ /* label = */ shortcutInfoWithRepeatedLabel.label,
+ /* keycode = */ KeyEvent.KEYCODE_M,
+ /* modifiers = */ KeyEvent.META_SHIFT_ON,
+ )
+
+ private val shortcutWithGroupedRepeatedLabel =
+ shortcut(shortcutInfoWithRepeatedLabel.label!!.toString()) {
+ command {
+ key(R.drawable.ic_ksh_key_meta)
+ key("H")
+ }
+ command {
+ key(R.drawable.ic_ksh_key_meta)
+ key("L")
+ }
+ command {
+ key("Shift")
+ key("M")
+ }
+ }
+
+ private val standardShortcutInfo1 =
+ KeyboardShortcutInfo(
+ /* label = */ "Standard shortcut 1",
+ /* keycode = */ KeyEvent.KEYCODE_N,
+ /* modifiers = */ KeyEvent.META_META_ON,
+ )
+
+ private val standardShortcut1 =
+ shortcut(standardShortcutInfo1.label!!.toString()) {
+ command {
+ key(R.drawable.ic_ksh_key_meta)
+ key("N")
+ }
+ }
+
+ private val standardShortcutInfo2 =
+ KeyboardShortcutInfo(
+ /* label = */ "Standard shortcut 2",
+ /* keycode = */ KeyEvent.KEYCODE_Z,
+ /* modifiers = */ KeyEvent.META_ALT_ON or KeyEvent.META_SHIFT_ON,
+ )
+
+ private val standardShortcut2 =
+ shortcut(standardShortcutInfo2.label!!.toString()) {
+ command {
+ key("Alt")
+ key("Shift")
+ key("Z")
+ }
+ }
+
+ private val standardShortcutInfo3 =
+ KeyboardShortcutInfo(
+ /* label = */ "Standard shortcut 3",
+ /* keycode = */ KeyEvent.KEYCODE_J,
+ /* modifiers = */ KeyEvent.META_CTRL_ON,
+ )
+
+ private val standardShortcut3 =
+ shortcut(standardShortcutInfo3.label!!.toString()) {
+ command {
+ key("Ctrl")
+ key("J")
+ }
+ }
+
+ private val shortcutInfoWithUnsupportedModifiers =
+ KeyboardShortcutInfo(
+ /* label = */ "Shortcut with unsupported modifiers",
+ /* keycode = */ KeyEvent.KEYCODE_A,
+ /* modifiers = */ KeyEvent.META_META_ON or KeyEvent.KEYCODE_SPACE,
+ )
+
+ private val groupWithRepeatedShortcutLabels =
+ KeyboardShortcutGroup(
+ "Group with duplicate labels",
+ listOf(
+ shortcutInfoWithRepeatedLabel,
+ shortcutInfoWithRepeatedLabelAlternate,
+ shortcutInfoWithRepeatedLabelSecondAlternate
+ )
+ )
+
+ private val subCategoryWithGroupedRepeatedShortcutLabels =
+ ShortcutSubCategory(
+ label = groupWithRepeatedShortcutLabels.label!!.toString(),
+ shortcuts = listOf(shortcutWithGroupedRepeatedLabel)
+ )
+
+ private val groupWithStandardShortcutInfo =
+ KeyboardShortcutGroup("Standard group", listOf(standardShortcutInfo1))
+
+ private val subCategoryWithStandardShortcut =
+ ShortcutSubCategory(
+ label = groupWithStandardShortcutInfo.label!!.toString(),
+ shortcuts = listOf(standardShortcut1)
+ )
+
+ private val groupWithOnlyUnsupportedModifierShortcut =
+ KeyboardShortcutGroup(
+ "Group with unsupported modifiers",
+ listOf(shortcutInfoWithUnsupportedModifiers)
+ )
+
+ private val groupWithSupportedAndUnsupportedModifierShortcut =
+ KeyboardShortcutGroup(
+ "Group with mix of supported and not supported modifiers",
+ listOf(standardShortcutInfo3, shortcutInfoWithUnsupportedModifiers)
+ )
+
+ private val subCategoryWithUnsupportedShortcutsRemoved =
+ ShortcutSubCategory(
+ groupWithSupportedAndUnsupportedModifierShortcut.label!!.toString(),
+ listOf(standardShortcut3)
+ )
+
+ private val standardGroup1 =
+ KeyboardShortcutGroup(
+ "Standard group 1",
+ listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3)
+ )
+
+ private val standardSubCategory1 =
+ ShortcutSubCategory(
+ standardGroup1.label!!.toString(),
+ listOf(standardShortcut1, standardShortcut2, standardShortcut3)
+ )
+
+ private val standardGroup2 =
+ KeyboardShortcutGroup(
+ "Standard group 2",
+ listOf(standardShortcutInfo3, standardShortcutInfo2, standardShortcutInfo1)
+ )
+
+ private val standardSubCategory2 =
+ ShortcutSubCategory(
+ standardGroup2.label!!.toString(),
+ listOf(standardShortcut3, standardShortcut2, standardShortcut1)
+ )
+ private val standardGroup3 =
+ KeyboardShortcutGroup(
+ "Standard group 3",
+ listOf(standardShortcutInfo2, standardShortcutInfo1)
+ )
+
+ private val standardSubCategory3 =
+ ShortcutSubCategory(
+ standardGroup3.label!!.toString(),
+ listOf(standardShortcut2, standardShortcut1)
+ )
+ val imeGroups = listOf(standardGroup1, standardGroup2, standardGroup3)
+ val imeCategory =
+ ShortcutCategory(
+ type = ShortcutCategoryType.IME,
+ subCategories = listOf(standardSubCategory1, standardSubCategory2, standardSubCategory3)
+ )
+
+ val systemGroups = listOf(standardGroup3, standardGroup2, standardGroup1)
+ val systemCategory =
+ ShortcutCategory(
+ type = ShortcutCategoryType.SYSTEM,
+ subCategories = listOf(standardSubCategory3, standardSubCategory2, standardSubCategory1)
+ )
+
+ val multitaskingGroups = listOf(standardGroup2, standardGroup1)
+ val multitaskingCategory =
+ ShortcutCategory(
+ type = ShortcutCategoryType.MULTI_TASKING,
+ subCategories = listOf(standardSubCategory2, standardSubCategory1)
+ )
+
+ val groupsWithDuplicateShortcutLabels =
+ listOf(groupWithRepeatedShortcutLabels, groupWithStandardShortcutInfo)
+
+ val subCategoriesWithGroupedDuplicatedShortcutLabels =
+ listOf(subCategoryWithGroupedRepeatedShortcutLabels, subCategoryWithStandardShortcut)
+
+ val groupsWithUnsupportedModifier =
+ listOf(
+ groupWithStandardShortcutInfo,
+ groupWithOnlyUnsupportedModifierShortcut,
+ groupWithSupportedAndUnsupportedModifierShortcut
+ )
+
+ val subCategoriesWithUnsupportedModifiersRemoved =
+ listOf(subCategoryWithStandardShortcut, subCategoryWithUnsupportedShortcutsRemoved)
+
+ val groupsWithOnlyUnsupportedModifiers = listOf(groupWithOnlyUnsupportedModifierShortcut)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
index c00e7e794d1c..c6a7565efcd7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
@@ -16,18 +16,16 @@
package com.android.systemui.keyboard.shortcut.domain.interactor
-import android.view.KeyEvent
-import android.view.KeyboardShortcutGroup
-import android.view.KeyboardShortcutInfo
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.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
-import com.android.systemui.keyboard.shortcut.shared.model.shortcut
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.IME
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MULTI_TASKING
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.SYSTEM
import com.android.systemui.keyboard.shortcut.shortcutHelperCategoriesInteractor
import com.android.systemui.keyboard.shortcut.shortcutHelperMultiTaskingShortcutsSource
import com.android.systemui.keyboard.shortcut.shortcutHelperSystemShortcutsSource
@@ -56,15 +54,16 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
it.shortcutHelperSystemShortcutsSource = systemShortcutsSource
it.shortcutHelperMultiTaskingShortcutsSource = multitaskingShortcutsSource
}
+
private val testScope = kosmos.testScope
private val interactor = kosmos.shortcutHelperCategoriesInteractor
private val helper = kosmos.shortcutHelperTestHelper
@Before
- fun setUp() {
- // Setting these sources as empty temporarily. Will be populated in follow up CL.
- systemShortcutsSource.setGroups(emptyList())
- multitaskingShortcutsSource.setGroups(emptyList())
+ fun setShortcuts() {
+ helper.setImeShortcuts(TestShortcuts.imeGroups)
+ systemShortcutsSource.setGroups(TestShortcuts.systemGroups)
+ multitaskingShortcutsSource.setGroups(TestShortcuts.multitaskingGroups)
}
@Test
@@ -78,12 +77,17 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
@Test
fun categories_stateActive_emitsAllCategoriesInOrder() =
testScope.runTest {
- helper.setImeShortcuts(imeShortcutGroups)
val categories by collectLastValue(interactor.shortcutCategories)
helper.showFromActivity()
- assertThat(categories).containsExactly(imeShortcutCategory).inOrder()
+ assertThat(categories)
+ .containsExactly(
+ TestShortcuts.systemCategory,
+ TestShortcuts.multitaskingCategory,
+ TestShortcuts.imeCategory,
+ )
+ .inOrder()
}
@Test
@@ -96,159 +100,177 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
assertThat(categories).isEmpty()
}
- fun categories_stateActive_emitsGroupedShortcuts() =
+ @Test
+ fun categories_stateActive_imeShortcutsWithDuplicateLabels_emitsGroupedShortcuts() =
testScope.runTest {
- helper.setImeShortcuts(imeShortcutsGroupsWithDuplicateLabels)
+ helper.setImeShortcuts(TestShortcuts.groupsWithDuplicateShortcutLabels)
+
val categories by collectLastValue(interactor.shortcutCategories)
helper.showFromActivity()
- assertThat(categories).containsExactly(expectedGroupedShortcutCategories)
+ assertThat(categories)
+ .containsExactly(
+ TestShortcuts.systemCategory,
+ TestShortcuts.multitaskingCategory,
+ ShortcutCategory(
+ type = IME,
+ subCategories =
+ TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
+ ),
+ )
+ .inOrder()
}
- private val switchToNextLanguageShortcut =
- shortcut(label = "switch to next language") {
- command(KeyEvent.META_CTRL_ON, KeyEvent.KEYCODE_SPACE)
- }
+ @Test
+ fun categories_stateActive_systemShortcutsWithDuplicateLabels_emitsGroupedShortcuts() =
+ testScope.runTest {
+ systemShortcutsSource.setGroups(TestShortcuts.groupsWithDuplicateShortcutLabels)
- private val switchToNextLanguageKeyboardShortcutInfo =
- KeyboardShortcutInfo(
- /* label = */ switchToNextLanguageShortcut.label,
- /* keycode = */ switchToNextLanguageShortcut.commands[0].keyCodes[1],
- /* modifiers = */ switchToNextLanguageShortcut.commands[0].keyCodes[0],
- )
+ val categories by collectLastValue(interactor.shortcutCategories)
- private val switchToNextLanguageShortcutAlternative =
- shortcut("switch to next language") {
- command(KeyEvent.META_CTRL_ON, KeyEvent.KEYCODE_SPACE)
- }
+ helper.showFromActivity()
- private val switchToNextLanguageKeyboardShortcutInfoAlternative =
- KeyboardShortcutInfo(
- /* label = */ switchToNextLanguageShortcutAlternative.label,
- /* keycode = */ switchToNextLanguageShortcutAlternative.commands[0].keyCodes[1],
- /* modifiers = */ switchToNextLanguageShortcutAlternative.commands[0].keyCodes[0],
- )
-
- private val switchToPreviousLanguageShortcut =
- shortcut("switch to previous language") {
- command(
- KeyEvent.META_SHIFT_ON,
- KeyEvent.KEYCODE_SPACE,
- )
+ assertThat(categories)
+ .containsExactly(
+ ShortcutCategory(
+ type = SYSTEM,
+ subCategories =
+ TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
+ ),
+ TestShortcuts.multitaskingCategory,
+ TestShortcuts.imeCategory,
+ )
+ .inOrder()
}
- private val switchToPreviousLanguageKeyboardShortcutInfo =
- KeyboardShortcutInfo(
- /* label = */ switchToPreviousLanguageShortcut.label,
- /* keycode = */ switchToPreviousLanguageShortcut.commands[0].keyCodes[1],
- /* modifiers = */ switchToPreviousLanguageShortcut.commands[0].keyCodes[0],
- )
-
- private val switchToPreviousLanguageShortcutAlternative =
- shortcut("switch to previous language") {
- command(
- KeyEvent.META_SHIFT_ON,
- KeyEvent.KEYCODE_SPACE,
- )
+ @Test
+ fun categories_stateActive_multiTaskingShortcutsWithDuplicateLabels_emitsGroupedShortcuts() =
+ testScope.runTest {
+ multitaskingShortcutsSource.setGroups(TestShortcuts.groupsWithDuplicateShortcutLabels)
+
+ val categories by collectLastValue(interactor.shortcutCategories)
+
+ helper.showFromActivity()
+
+ assertThat(categories)
+ .containsExactly(
+ TestShortcuts.systemCategory,
+ ShortcutCategory(
+ type = MULTI_TASKING,
+ subCategories =
+ TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
+ ),
+ TestShortcuts.imeCategory,
+ )
+ .inOrder()
}
- private val switchToPreviousLanguageKeyboardShortcutInfoAlternative =
- KeyboardShortcutInfo(
- /* label = */ switchToPreviousLanguageShortcutAlternative.label,
- /* keycode = */ switchToPreviousLanguageShortcutAlternative.commands[0].keyCodes[1],
- /* modifiers = */ switchToPreviousLanguageShortcutAlternative.commands[0].keyCodes[0],
- )
+ @Test
+ fun categories_stateActive_imeShortcutsWithUnsupportedModifiers_discardUnsupported() =
+ testScope.runTest {
+ helper.setImeShortcuts(TestShortcuts.groupsWithUnsupportedModifier)
+ val categories by collectLastValue(interactor.shortcutCategories)
+
+ helper.showFromActivity()
- private val showOnscreenKeyboardShortcut =
- shortcut(label = "Show on-screen keyboard") {
- command(KeyEvent.META_ALT_ON, KeyEvent.KEYCODE_K)
+ assertThat(categories)
+ .containsExactly(
+ TestShortcuts.systemCategory,
+ TestShortcuts.multitaskingCategory,
+ ShortcutCategory(
+ type = IME,
+ subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
+ ),
+ )
+ .inOrder()
}
- private val showOnScreenKeyboardShortcutInfo =
- KeyboardShortcutInfo(
- /* label = */ showOnscreenKeyboardShortcut.label,
- /* keycode = */ showOnscreenKeyboardShortcut.commands[0].keyCodes[1],
- /* modifiers = */ showOnscreenKeyboardShortcut.commands[0].keyCodes[0],
- )
-
- private val accessClipboardShortcut =
- shortcut(label = "Access clipboard") { command(KeyEvent.META_ALT_ON, KeyEvent.KEYCODE_V) }
-
- private val accessClipboardShortcutInfo =
- KeyboardShortcutInfo(
- /* label = */ accessClipboardShortcut.label,
- /* keycode = */ accessClipboardShortcut.commands[0].keyCodes[1],
- /* modifiers = */ accessClipboardShortcut.commands[0].keyCodes[0],
- )
-
- private val imeShortcutGroups =
- listOf(
- KeyboardShortcutGroup(
- /* label = */ "input",
- /* shortcutInfoList = */ listOf(
- switchToNextLanguageKeyboardShortcutInfo,
- switchToPreviousLanguageKeyboardShortcutInfo
+ @Test
+ fun categories_stateActive_systemShortcutsWithUnsupportedModifiers_discardUnsupported() =
+ testScope.runTest {
+ systemShortcutsSource.setGroups(TestShortcuts.groupsWithUnsupportedModifier)
+ val categories by collectLastValue(interactor.shortcutCategories)
+
+ helper.showFromActivity()
+
+ assertThat(categories)
+ .containsExactly(
+ ShortcutCategory(
+ type = SYSTEM,
+ subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
+ ),
+ TestShortcuts.multitaskingCategory,
+ TestShortcuts.imeCategory,
)
- )
- )
-
- private val imeShortcutCategory =
- ShortcutCategory(
- type = ShortcutCategoryType.IME,
- subCategories =
- listOf(
- ShortcutSubCategory(
- imeShortcutGroups[0].label.toString(),
- listOf(switchToNextLanguageShortcut, switchToPreviousLanguageShortcut)
- )
+ .inOrder()
+ }
+
+ @Test
+ fun categories_stateActive_multitaskingShortcutsWithUnsupportedModifiers_discardUnsupported() =
+ testScope.runTest {
+ multitaskingShortcutsSource.setGroups(TestShortcuts.groupsWithUnsupportedModifier)
+ val categories by collectLastValue(interactor.shortcutCategories)
+
+ helper.showFromActivity()
+
+ assertThat(categories)
+ .containsExactly(
+ TestShortcuts.systemCategory,
+ ShortcutCategory(
+ type = MULTI_TASKING,
+ subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
+ ),
+ TestShortcuts.imeCategory,
)
- )
-
- private val imeShortcutsGroupsWithDuplicateLabels =
- listOf(
- KeyboardShortcutGroup(
- "input",
- listOf(
- switchToNextLanguageKeyboardShortcutInfo,
- switchToNextLanguageKeyboardShortcutInfoAlternative,
- switchToPreviousLanguageKeyboardShortcutInfo,
- switchToPreviousLanguageKeyboardShortcutInfoAlternative
+ .inOrder()
+ }
+
+ @Test
+ fun categories_stateActive_imeShortcutsWitOnlyUnsupportedModifiers_discardsCategory() =
+ testScope.runTest {
+ helper.setImeShortcuts(TestShortcuts.groupsWithOnlyUnsupportedModifiers)
+ val categories by collectLastValue(interactor.shortcutCategories)
+
+ helper.showFromActivity()
+
+ assertThat(categories)
+ .containsExactly(
+ TestShortcuts.systemCategory,
+ TestShortcuts.multitaskingCategory,
)
- ),
- KeyboardShortcutGroup(
- "Gboard",
- listOf(
- showOnScreenKeyboardShortcutInfo,
- accessClipboardShortcutInfo,
+ .inOrder()
+ }
+
+ @Test
+ fun categories_stateActive_systemShortcutsWitOnlyUnsupportedModifiers_discardsCategory() =
+ testScope.runTest {
+ systemShortcutsSource.setGroups(TestShortcuts.groupsWithOnlyUnsupportedModifiers)
+ val categories by collectLastValue(interactor.shortcutCategories)
+
+ helper.showFromActivity()
+
+ assertThat(categories)
+ .containsExactly(
+ TestShortcuts.multitaskingCategory,
+ TestShortcuts.imeCategory,
)
- )
- )
-
- private val expectedGroupedShortcutCategories =
- ShortcutCategory(
- type = ShortcutCategoryType.IME,
- subCategories =
- listOf(
- ShortcutSubCategory(
- imeShortcutsGroupsWithDuplicateLabels[0].label.toString(),
- listOf(
- switchToNextLanguageShortcut.copy(
- commands =
- switchToNextLanguageShortcut.commands +
- switchToNextLanguageShortcutAlternative.commands
- ),
- switchToPreviousLanguageShortcut.copy(
- commands =
- switchToPreviousLanguageShortcut.commands +
- switchToPreviousLanguageShortcutAlternative.commands
- )
- ),
- ),
- ShortcutSubCategory(
- imeShortcutsGroupsWithDuplicateLabels[1].label.toString(),
- listOf(showOnscreenKeyboardShortcut, accessClipboardShortcut),
- )
+ .inOrder()
+ }
+
+ @Test
+ fun categories_stateActive_multitaskingShortcutsWitOnlyUnsupportedModifiers_discardsCategory() =
+ testScope.runTest {
+ multitaskingShortcutsSource.setGroups(TestShortcuts.groupsWithOnlyUnsupportedModifiers)
+ val categories by collectLastValue(interactor.shortcutCategories)
+
+ helper.showFromActivity()
+
+ assertThat(categories)
+ .containsExactly(
+ TestShortcuts.systemCategory,
+ TestShortcuts.imeCategory,
)
- )
+ .inOrder()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
index f32e7757328f..c9871f1e4e1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
@@ -21,6 +21,9 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
@@ -28,12 +31,18 @@ import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.util.mockTopActivityClassName
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.repository.Idle
+import com.android.systemui.scene.data.repository.Transition
+import com.android.systemui.scene.data.repository.setSceneTransition
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.shared.system.activityManagerWrapper
import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.assertValuesMatch
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -44,16 +53,22 @@ import org.junit.runner.RunWith
@kotlinx.coroutines.ExperimentalCoroutinesApi
class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
private val kosmos = testKosmos()
- private val testScope = kosmos.testScope
- private val underTest = kosmos.keyguardSurfaceBehindInteractor
- private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
- private val inWindowUnlockInteractor = kosmos.inWindowLauncherUnlockAnimationInteractor
- private val activityManagerWrapper = kosmos.activityManagerWrapper
+ private lateinit var testScope: TestScope
+ private lateinit var underTest: KeyguardSurfaceBehindInteractor
+ private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+ private lateinit var inWindowUnlockInteractor: InWindowLauncherUnlockAnimationInteractor
+ private lateinit var activityManagerWrapper: ActivityManagerWrapper
private val LAUNCHER_ACTIVITY_NAME = "launcher"
@Before
fun setUp() {
+ testScope = kosmos.testScope
+ underTest = kosmos.keyguardSurfaceBehindInteractor
+ transitionRepository = kosmos.fakeKeyguardTransitionRepository
+ inWindowUnlockInteractor = kosmos.inWindowLauncherUnlockAnimationInteractor
+ activityManagerWrapper = kosmos.activityManagerWrapper
+
inWindowUnlockInteractor.setLauncherActivityClass(LAUNCHER_ACTIVITY_NAME)
// Default to having something other than Launcher on top.
@@ -61,6 +76,7 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun testSurfaceBehindModel_toAppSurface() =
testScope.runTest {
val values by collectValues(underTest.viewParams)
@@ -136,6 +152,7 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun testSurfaceBehindModel_toLauncher() =
testScope.runTest {
val values by collectValues(underTest.viewParams)
@@ -196,6 +213,7 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun testSurfaceBehindModel_fromNotificationLaunch() =
testScope.runTest {
val values by collectValues(underTest.viewParams)
@@ -230,6 +248,105 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
}
@Test
+ @EnableSceneContainer
+ fun testSurfaceBehindModel_toAppSurface_scene_container() =
+ testScope.runTest {
+ val values by collectValues(underTest.viewParams)
+ runCurrent()
+
+ assertThat(values)
+ .containsExactly(
+ // We're initialized in LOCKSCREEN.
+ KeyguardSurfaceBehindModel(alpha = 0f),
+ )
+
+ kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))
+
+ values.assertValuesMatch(
+ { it == KeyguardSurfaceBehindModel(alpha = 0f) },
+ // Once we start a transition to GONE, we should fade in and translate up. The exact
+ // start value depends on screen density, so just look for != 0.
+ {
+ it.animateFromAlpha == 0f &&
+ it.alpha == 1f &&
+ it.animateFromTranslationY != 0f &&
+ it.translationY == 0f
+ }
+ )
+
+ kosmos.setSceneTransition(Idle(Scenes.Gone))
+
+ values.assertValuesMatch(
+ { it == KeyguardSurfaceBehindModel(alpha = 0f) },
+ {
+ it.animateFromAlpha == 0f &&
+ it.alpha == 1f &&
+ it.animateFromTranslationY != 0f &&
+ it.translationY == 0f
+ },
+ // Once the current state is GONE, we should default to alpha = 1f.
+ { it == KeyguardSurfaceBehindModel(alpha = 1f) }
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun testSurfaceBehindModel_toLauncher_scene_container() =
+ testScope.runTest {
+ val values by collectValues(underTest.viewParams)
+ activityManagerWrapper.mockTopActivityClassName(LAUNCHER_ACTIVITY_NAME)
+ runCurrent()
+
+ assertThat(values)
+ .containsExactly(
+ // We're initialized in LOCKSCREEN.
+ KeyguardSurfaceBehindModel(alpha = 0f),
+ )
+ .inOrder()
+
+ kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))
+
+ assertThat(values)
+ .containsExactly(
+ KeyguardSurfaceBehindModel(alpha = 0f),
+ // We should instantly set alpha = 1, with no animations, when Launcher is
+ // behind
+ // the keyguard since we're playing in-window animations.
+ KeyguardSurfaceBehindModel(alpha = 1f),
+ )
+ .inOrder()
+
+ kosmos.setSceneTransition(Idle(Scenes.Gone))
+
+ assertThat(values)
+ .containsExactly(
+ KeyguardSurfaceBehindModel(alpha = 0f),
+ // Should have remained at alpha = 1f through the entire animation.
+ KeyguardSurfaceBehindModel(alpha = 1f),
+ )
+ .inOrder()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun testSurfaceBehindModel_fromNotificationLaunch_scene_container() =
+ testScope.runTest {
+ val values by collectValues(underTest.viewParams)
+ runCurrent()
+
+ kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(true)
+ runCurrent()
+
+ kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))
+
+ values.assertValuesMatch(
+ // We should be at alpha = 0f during the animation.
+ { it == KeyguardSurfaceBehindModel(alpha = 0f) },
+ )
+ }
+
+ @Test
+ @DisableSceneContainer
fun notificationLaunchFromLockscreen_isAnimatingSurfaceTrue() =
testScope.runTest {
val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
@@ -253,6 +370,7 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun notificationLaunchFromGone_isAnimatingSurfaceFalse() =
testScope.runTest {
val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
@@ -276,6 +394,7 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun notificationLaunchFalse_isAnimatingSurfaceFalse() =
testScope.runTest {
val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
@@ -297,4 +416,44 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
runCurrent()
assertThat(isAnimatingSurface).isFalse()
}
+
+ @Test
+ @EnableSceneContainer
+ fun notificationLaunchFromLockscreen_isAnimatingSurfaceTrue_scene_container() =
+ testScope.runTest {
+ val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
+
+ kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
+ kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(true)
+ runCurrent()
+
+ assertThat(isAnimatingSurface).isTrue()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun notificationLaunchFromGone_isAnimatingSurfaceFalse_scene_container() =
+ testScope.runTest {
+ val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
+
+ kosmos.setSceneTransition(Idle(Scenes.Gone))
+ kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(true)
+ runCurrent()
+ assertThat(isAnimatingSurface).isFalse()
+
+ kosmos.setSceneTransition(Transition(from = Scenes.Gone, to = Scenes.Lockscreen))
+ assertThat(isAnimatingSurface).isFalse()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun notificationLaunchFalse_isAnimatingSurfaceFalse_scene_container() =
+ testScope.runTest {
+ val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
+
+ kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
+ kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(false)
+ runCurrent()
+ assertThat(isAnimatingSurface).isFalse()
+ }
}
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 246cfbfbea68..824132adc0d5 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
@@ -30,7 +30,6 @@ import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepositor
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.dock.fakeDockManager
import com.android.systemui.flags.BrokenWithSceneContainer
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.FakeFeatureFlags
@@ -124,7 +123,6 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
private val powerInteractor by lazy { kosmos.powerInteractor }
private val communalInteractor by lazy { kosmos.communalInteractor }
- private val dockManager by lazy { kosmos.fakeDockManager }
companion object {
@JvmStatic
@@ -583,6 +581,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
}
@Test
+ @DisableSceneContainer
fun dozingToPrimaryBouncer() =
testScope.runTest {
// GIVEN a prior transition has run to DOZING
@@ -597,8 +596,8 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
assertThat(transitionRepository)
.startedTransition(
- to = KeyguardState.PRIMARY_BOUNCER,
from = KeyguardState.DOZING,
+ to = KeyguardState.PRIMARY_BOUNCER,
animatorAssertion = { it.isNotNull() }
)
@@ -633,6 +632,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
}
@Test
+ @DisableSceneContainer
fun dozingToGlanceableHub() =
testScope.runTest {
// GIVEN a prior transition has run to DOZING
@@ -654,8 +654,8 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
assertThat(transitionRepository)
.startedTransition(
- to = KeyguardState.GLANCEABLE_HUB,
from = KeyguardState.DOZING,
+ to = KeyguardState.GLANCEABLE_HUB,
animatorAssertion = { it.isNotNull() }
)
@@ -1452,6 +1452,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
}
@Test
+ @DisableSceneContainer
fun dreamingToPrimaryBouncer() =
testScope.runTest {
// GIVEN a prior transition has run to DREAMING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
index f624f2029b36..b7fb759eb138 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
@@ -57,7 +57,9 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.anyString
+import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
@@ -75,6 +77,9 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
private lateinit var mockitoSession: MockitoSession
+ private val spiedContext = spy(context)
+ private val spiedResources = spy(spiedContext.resources)
+
@Before
fun setUp() {
mockitoSession =
@@ -100,6 +105,8 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
)
)
.thenReturn(listOf("com.google.test.notes"))
+
+ `when`(spiedContext.resources).thenReturn(spiedResources)
}
@After
@@ -109,7 +116,7 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
private fun createUnderTest(isEnabled: Boolean = true): KeyguardQuickAffordanceConfig =
NoteTaskQuickAffordanceConfig(
- context = context,
+ context = spiedContext,
controller = controller,
stylusManager = stylusManager,
userManager = userManager,
@@ -132,126 +139,262 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
)
// region lockScreenState
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_stylusUsed_userUnlocked_isSelected_shouldEmitVisible() = runTest {
- val underTest = createUnderTest()
- TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(underTest)
+ fun lockScreenState_stylusUnused_userLocked_customizationDisabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(false)
+ .setUserUnlocked(false)
+ .setLockScreenCustomizationEnabled(false)
+ .setConfigSelections()
- val actual by collectLastValue(underTest.lockScreenState)
+ val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(createLockScreenStateVisible())
- }
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_stylusUsed_userUnlocked_isSelected_noDefaultNotesAppSet_shouldEmitHidden() =
+ fun lockScreenState_stylusUnused_userLocked_customizationDisabled_notesLockScreenShortcutSelected_shouldEmitHidden() =
runTest {
val underTest = createUnderTest()
TestConfig()
- .setStylusEverUsed(true)
+ .setStylusEverUsed(false)
+ .setUserUnlocked(false)
+ .setLockScreenCustomizationEnabled(false)
+ .setConfigSelections(underTest)
+
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Suppress("ktlint:standard:max-line-length")
+ @Test
+ fun lockScreenState_stylusUnused_userLocked_customizationEnabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(false)
+ .setUserUnlocked(false)
+ .setLockScreenCustomizationEnabled(true)
+ .setConfigSelections()
+
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Suppress("ktlint:standard:max-line-length")
+ @Test
+ fun lockScreenState_stylusUnused_userLocked_customizationEnabled_notesLockScreenShortcutSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(false)
+ .setUserUnlocked(false)
+ .setLockScreenCustomizationEnabled(true)
+ .setConfigSelections(underTest)
+
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Suppress("ktlint:standard:max-line-length")
+ @Test
+ fun lockScreenState_stylusUnused_userUnlocked_customizationDisabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(false)
.setUserUnlocked(true)
+ .setLockScreenCustomizationEnabled(false)
+ .setConfigSelections()
+
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Suppress("ktlint:standard:max-line-length")
+ @Test
+ fun lockScreenState_stylusUnused_userUnlocked_customizationDisabled_notesLockScreenShortcutSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(false)
+ .setUserUnlocked(true)
+ .setLockScreenCustomizationEnabled(false)
.setConfigSelections(underTest)
- whenever(
- roleManager.getRoleHoldersAsUser(
- eq(RoleManager.ROLE_NOTES),
- any(UserHandle::class.java)
- )
- )
- .thenReturn(emptyList())
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_stylusUnused_userUnlocked_isSelected_shouldEmitHidden() = runTest {
- val underTest = createUnderTest()
- TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections(underTest)
+ fun lockScreenState_stylusUnused_userUnlocked_customizationEnabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(false)
+ .setUserUnlocked(true)
+ .setLockScreenCustomizationEnabled(true)
+ .setConfigSelections()
- val actual by collectLastValue(underTest.lockScreenState)
+ val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(LockScreenState.Hidden)
- }
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_stylusUsed_userLocked_isSelected_shouldEmitHidden() = runTest {
- val underTest = createUnderTest()
- TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections(underTest)
+ fun lockScreenState_stylusUnused_userUnlocked_customizationEnabled_notesLockScreenShortcutSelected_shouldEmitVisible() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(false)
+ .setUserUnlocked(true)
+ .setLockScreenCustomizationEnabled(true)
+ .setConfigSelections(underTest)
- val actual by collectLastValue(underTest.lockScreenState)
+ val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(LockScreenState.Hidden)
- }
+ assertThat(actual).isEqualTo(createLockScreenStateVisible())
+ }
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_stylusUsed_userUnlocked_noSelected_shouldEmitHidden() = runTest {
- TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections()
+ fun lockScreenState_stylusUsed_userLocked_customizationDisabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(false)
+ .setLockScreenCustomizationEnabled(false)
+ .setConfigSelections()
- val underTest = createUnderTest()
- val actual by collectLastValue(underTest.lockScreenState)
+ val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(LockScreenState.Hidden)
- }
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_stylusUnused_userUnlocked_noSelected_shouldEmitHidden() = runTest {
- TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections()
+ fun lockScreenState_stylusUsed_userLocked_customizationDisabled_notesLockScreenShortcutSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(false)
+ .setLockScreenCustomizationEnabled(false)
+ .setConfigSelections(underTest)
- val underTest = createUnderTest()
- val actual by collectLastValue(underTest.lockScreenState)
+ val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(LockScreenState.Hidden)
- }
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_stylusUsed_userLocked_noSelected_shouldEmitHidden() = runTest {
- TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections()
+ fun lockScreenState_stylusUsed_userLocked_customizationEnabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(false)
+ .setLockScreenCustomizationEnabled(true)
+ .setConfigSelections()
- val underTest = createUnderTest()
- val actual by collectLastValue(underTest.lockScreenState)
+ val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(LockScreenState.Hidden)
- }
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_stylusUsed_userUnlocked_customSelections_shouldEmitHidden() = runTest {
- TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(mock())
+ fun lockScreenState_stylusUsed_userLocked_customizationEnabled_notesLockScreenShortcutSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(false)
+ .setLockScreenCustomizationEnabled(true)
+ .setConfigSelections(underTest)
- val underTest = createUnderTest()
- val actual by collectLastValue(underTest.lockScreenState)
+ val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(LockScreenState.Hidden)
- }
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_stylusUnused_userUnlocked_customSelections_shouldEmitHidden() = runTest {
- TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections(mock())
+ fun lockScreenState_stylusUsed_userUnlocked_customizationDisabled_notesLockScreenShortcutNotSelected_shouldEmitVisible() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(true)
+ .setLockScreenCustomizationEnabled(false)
+ .setConfigSelections()
- val underTest = createUnderTest()
- val actual by collectLastValue(underTest.lockScreenState)
+ val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(LockScreenState.Hidden)
- }
+ assertThat(actual).isEqualTo(createLockScreenStateVisible())
+ }
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_stylusUsed_userLocked_customSelections_shouldEmitHidden() = runTest {
- TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections(mock())
+ fun lockScreenState_stylusUsed_userUnlocked_customizationDisabled_notesLockScreenShortcutSelected_shouldEmitVisible() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(true)
+ .setLockScreenCustomizationEnabled(false)
+ .setConfigSelections(underTest)
- val underTest = createUnderTest()
- val actual by collectLastValue(underTest.lockScreenState)
+ val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(LockScreenState.Hidden)
- }
+ assertThat(actual).isEqualTo(createLockScreenStateVisible())
+ }
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun lockScreenState_isNotEnabled_shouldEmitHidden() = runTest {
- TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections()
+ fun lockScreenState_stylusUsed_userUnlocked_customizationEnabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(true)
+ .setLockScreenCustomizationEnabled(true)
+ .setConfigSelections()
- val underTest = createUnderTest(isEnabled = false)
- val actual by collectLastValue(underTest.lockScreenState)
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Suppress("ktlint:standard:max-line-length")
+ @Test
+ fun lockScreenState_stylusUsed_userUnlocked_customizationEnabled_notesLockScreenShortcutSelected_shouldEmitVisible() =
+ runTest {
+ val underTest = createUnderTest()
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(true)
+ .setLockScreenCustomizationEnabled(true)
+ .setConfigSelections(underTest)
+
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(createLockScreenStateVisible())
+ }
- assertThat(actual).isEqualTo(LockScreenState.Hidden)
- }
// endregion
@Test
@@ -294,18 +437,24 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
.isEqualTo(ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE)
assertThat(disabled.actionIntent?.`package`).isEqualTo(context.packageName)
}
+
// endregion
private inner class TestConfig {
fun setStylusEverUsed(value: Boolean) = also {
- whenever(InputSettings.isStylusEverUsed(mContext)).thenReturn(value)
+ whenever(InputSettings.isStylusEverUsed(spiedContext)).thenReturn(value)
}
fun setUserUnlocked(value: Boolean) = also {
whenever(userManager.isUserUnlocked).thenReturn(value)
}
+ fun setLockScreenCustomizationEnabled(value: Boolean) = also {
+ `when`(spiedResources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled))
+ .thenReturn(value)
+ }
+
fun setConfigSelections(vararg values: KeyguardQuickAffordanceConfig) = also {
val slotKey = "bottom-right"
val configSnapshots = values.toList()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 5c45b2e53047..3669e3d8fed1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -64,6 +64,10 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
@Mock private SectionHeaderController mPeopleHeaderController;
@Mock private SectionHeaderController mAlertingHeaderController;
@Mock private SectionHeaderController mSilentHeaderController;
+ @Mock private SectionHeaderController mNewsHeaderController;
+ @Mock private SectionHeaderController mSocialHeaderController;
+ @Mock private SectionHeaderController mRecsHeaderController;
+ @Mock private SectionHeaderController mPromoHeaderController;
private NotificationSectionsManager mSectionsManager;
@@ -94,7 +98,11 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
mIncomingHeaderController,
mPeopleHeaderController,
mAlertingHeaderController,
- mSilentHeaderController
+ mSilentHeaderController,
+ mNewsHeaderController,
+ mSocialHeaderController,
+ mRecsHeaderController,
+ mPromoHeaderController
);
// Required in order for the header inflation to work properly
when(mNssl.generateLayoutParams(any(AttributeSet.class)))
diff --git a/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt b/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt
index 36ac4a469566..c4f93d107dbb 100644
--- a/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt
+++ b/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt
@@ -18,6 +18,7 @@ package android.hardware.input
import android.view.InputDevice
import android.view.KeyCharacterMap
+import android.view.KeyCharacterMap.VIRTUAL_KEYBOARD
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import org.mockito.ArgumentMatchers.anyInt
@@ -25,7 +26,18 @@ import org.mockito.invocation.InvocationOnMock
class FakeInputManager {
- private val devices = mutableMapOf<Int, InputDevice>()
+ private val keyCharacterMap = KeyCharacterMap.load(VIRTUAL_KEYBOARD)
+
+ private val virtualKeyboard =
+ InputDevice.Builder()
+ .setId(VIRTUAL_KEYBOARD)
+ .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC)
+ .setSources(InputDevice.SOURCE_KEYBOARD)
+ .setEnabled(true)
+ .setKeyCharacterMap(keyCharacterMap)
+ .build()
+
+ private val devices = mutableMapOf<Int, InputDevice>(VIRTUAL_KEYBOARD to virtualKeyboard)
val inputManager =
mock<InputManager> {
@@ -56,10 +68,6 @@ class FakeInputManager {
addKeyboard(id, enabled)
}
- fun addVirtualKeyboard(enabled: Boolean = true) {
- addKeyboard(id = KeyCharacterMap.VIRTUAL_KEYBOARD, enabled)
- }
-
private fun addKeyboard(id: Int, enabled: Boolean = true) {
devices[id] =
InputDevice.Builder()
@@ -67,6 +75,7 @@ class FakeInputManager {
.setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC)
.setSources(InputDevice.SOURCE_KEYBOARD)
.setEnabled(enabled)
+ .setKeyCharacterMap(keyCharacterMap)
.build()
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
index 9dae44dc8053..7c53639a85a6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
@@ -18,6 +18,7 @@ package com.android.systemui
import android.app.ActivityManager
import android.app.admin.DevicePolicyManager
import android.app.trust.TrustManager
+import android.hardware.fingerprint.FingerprintManager
import android.os.UserManager
import android.service.notification.NotificationListenerService
import android.util.DisplayMetrics
@@ -94,6 +95,7 @@ data class TestMocksModule(
@get:Provides val deviceProvisionedController: DeviceProvisionedController = mock(),
@get:Provides val dozeParameters: DozeParameters = mock(),
@get:Provides val dumpManager: DumpManager = mock(),
+ @get:Provides val fingerprintManager: FingerprintManager = mock(),
@get:Provides val headsUpManager: HeadsUpManager = mock(),
@get:Provides val guestResumeSessionReceiver: GuestResumeSessionReceiver = mock(),
@get:Provides val keyguardBypassController: KeyguardBypassController = mock(),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt
index cbfc7686a896..ae592b968f8b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt
@@ -17,17 +17,20 @@
package com.android.systemui.biometrics.domain.interactor
import android.content.applicationContext
+import android.hardware.fingerprint.FingerprintManager
import com.android.systemui.biometrics.authController
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.user.domain.interactor.selectedUserInteractor
+import com.android.systemui.util.mockito.mock
val Kosmos.udfpsOverlayInteractor by Fixture {
UdfpsOverlayInteractor(
context = applicationContext,
authController = authController,
selectedUserInteractor = selectedUserInteractor,
+ fingerprintManager = mock<FingerprintManager>(),
scope = applicationCoroutineScope,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
index 385a6dc5a819..dab70f86be09 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
@@ -59,10 +59,13 @@ val Kosmos.shortcutHelperStateRepository by
val Kosmos.shortcutHelperCategoriesRepository by
Kosmos.Fixture {
ShortcutHelperCategoriesRepository(
+ applicationContext,
+ testDispatcher,
shortcutHelperSystemShortcutsSource,
shortcutHelperMultiTaskingShortcutsSource,
windowManager,
- shortcutHelperStateRepository
+ fakeInputManager.inputManager,
+ shortcutHelperStateRepository,
)
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java
index 63bcda188ee6..4992c4bcc77a 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java
@@ -447,14 +447,6 @@ public class RavenwoodBaseContext extends Context {
}
@Override
- public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
- String[] receiverPermissions, int appOp, Bundle options,
- BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
- String initialData, Bundle initialExtras) {
- throw notSupported();
- }
-
- @Override
public void sendStickyBroadcast(Intent intent) {
throw notSupported();
}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index c4d38e46da3c..a2bbff026b95 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -48,3 +48,6 @@ per-file VcnManagementService.java = file:/services/core/java/com/android/server
# SystemConfig
per-file SystemConfig.java = file:/PACKAGE_MANAGER_OWNERS
+
+# CertBlocklister
+per-file Cert*.java = tweek@google.com, brambonne@google.com, prb@google.com, miguelaranda@google.com
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index a4026eb151b9..c2cb5e90ca58 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -803,22 +803,28 @@ public class RescueParty {
@Override
public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
@FailureReasons int failureReason, int mitigationCount) {
+ int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
if (Flags.recoverabilityDetection()) {
if (!Flags.deprecateFlagsAndSettingsResets()) {
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ impact = mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
mayPerformReboot(failedPackage), failedPackage));
} else {
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+ impact = mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
}
} else {
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ impact = mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
mayPerformReboot(failedPackage)));
}
- } else {
- return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
}
+
+ Slog.i(TAG, "Checking available remediations for health check failure."
+ + " failedPackage: "
+ + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " failureReason: " + failureReason
+ + " available impact: " + impact);
+ return impact;
}
@Override
@@ -827,6 +833,11 @@ public class RescueParty {
if (isDisabled()) {
return false;
}
+ Slog.i(TAG, "Executing remediation."
+ + " failedPackage: "
+ + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " failureReason: " + failureReason
+ + " mitigationCount: " + mitigationCount);
if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
final int level;
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index 598f086db94d..4faadcbe0cca 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -91,10 +91,18 @@ public class LmkdConnection {
@GuardedBy("mLmkdSocketLock")
private LocalSocket mLmkdSocket = null;
- // socket I/O streams
- @GuardedBy("mLmkdSocketLock")
+ // mutex to synchronize socket output stream with socket creation/destruction
+ private final Object mLmkdOutputStreamLock = new Object();
+
+ // socket output stream
+ @GuardedBy("mLmkdOutputStreamLock")
private OutputStream mLmkdOutputStream = null;
- @GuardedBy("mLmkdSocketLock")
+
+ // mutex to synchronize socket input stream with socket creation/destruction
+ private final Object mLmkdInputStreamLock = new Object();
+
+ // socket input stream
+ @GuardedBy("mLmkdInputStreamLock")
private InputStream mLmkdInputStream = null;
// buffer to store incoming data
@@ -148,9 +156,13 @@ public class LmkdConnection {
return false;
}
// connection established
- mLmkdSocket = socket;
- mLmkdOutputStream = ostream;
- mLmkdInputStream = istream;
+ synchronized(mLmkdOutputStreamLock) {
+ synchronized(mLmkdInputStreamLock) {
+ mLmkdSocket = socket;
+ mLmkdOutputStream = ostream;
+ mLmkdInputStream = istream;
+ }
+ }
mMsgQueue.addOnFileDescriptorEventListener(mLmkdSocket.getFileDescriptor(),
EVENT_INPUT | EVENT_ERROR,
new MessageQueue.OnFileDescriptorEventListener() {
@@ -177,7 +189,13 @@ public class LmkdConnection {
mMsgQueue.removeOnFileDescriptorEventListener(
mLmkdSocket.getFileDescriptor());
IoUtils.closeQuietly(mLmkdSocket);
- mLmkdSocket = null;
+ synchronized(mLmkdOutputStreamLock) {
+ synchronized(mLmkdInputStreamLock) {
+ mLmkdOutputStream = null;
+ mLmkdInputStream = null;
+ mLmkdSocket = null;
+ }
+ }
}
// wake up reply waiters if any
synchronized (mReplyBufLock) {
@@ -262,24 +280,33 @@ public class LmkdConnection {
}
private boolean write(ByteBuffer buf) {
- synchronized (mLmkdSocketLock) {
- try {
- mLmkdOutputStream.write(buf.array(), 0, buf.position());
- } catch (IOException ex) {
- return false;
+ boolean result = false;
+
+ synchronized(mLmkdOutputStreamLock) {
+ if (mLmkdOutputStream != null) {
+ try {
+ mLmkdOutputStream.write(buf.array(), 0, buf.position());
+ result = true;
+ } catch (IOException ex) {
+ }
}
- return true;
}
+
+ return result;
}
private int read(ByteBuffer buf) {
- synchronized (mLmkdSocketLock) {
- try {
- return mLmkdInputStream.read(buf.array(), 0, buf.array().length);
- } catch (IOException ex) {
+ int result = -1;
+
+ synchronized(mLmkdInputStreamLock) {
+ if (mLmkdInputStream != null) {
+ try {
+ result = mLmkdInputStream.read(buf.array(), 0, buf.array().length);
+ } catch (IOException ex) {
+ }
}
- return -1;
}
+ return result;
}
/**
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index d061e2d21811..fbd32a67fe6c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -31,7 +31,6 @@ import android.util.Slog;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
-import com.android.server.biometrics.sensors.fingerprint.aidl.AidlSession;
import java.util.function.Supplier;
@@ -203,16 +202,6 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement
}
}
- // TODO(b/317414324): Deprecate setIgnoreDisplayTouches
- protected final void resetIgnoreDisplayTouches() {
- final AidlSession session = (AidlSession) getFreshDaemon();
- try {
- session.getSession().setIgnoreDisplayTouches(false);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when resetting setIgnoreDisplayTouches");
- }
- }
-
@Override
public boolean isInterruptable() {
return true;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 4c86f57a190b..60cfd5a5a6ae 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -962,6 +962,19 @@ public class FingerprintService extends SystemService {
provider.onUdfpsUiEvent(event, requestId, sensorId);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
+ @Override
+ public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches) {
+ super.setIgnoreDisplayTouches_enforcePermission();
+
+ final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG,
+ "No matching provider for setIgnoreDisplayTouches, sensorId: " + sensorId);
+ return;
+ }
+ provider.setIgnoreDisplayTouches(requestId, sensorId, ignoreTouches);
+ }
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index a6cf2f4b31ae..e4a99e6be72c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -134,6 +134,8 @@ public interface ServiceProvider extends
void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
+ void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches);
+
void onPowerPressed();
@NonNull
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
index dce0175ca593..15d7a476b345 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
@@ -31,4 +31,5 @@ public interface Udfps {
void onPointerUp(PointerContext pc);
void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event);
boolean isPointerDown();
+ void setIgnoreDisplayTouches(boolean ignoreTouches);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 72d92b974c1a..d04afdb72913 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -33,7 +33,6 @@ import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcqu
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.common.ICancellationSignal;
-import android.hardware.biometrics.common.OperationState;
import android.hardware.biometrics.events.AuthenticationAcquiredInfo;
import android.hardware.biometrics.events.AuthenticationErrorInfo;
import android.hardware.biometrics.events.AuthenticationFailedInfo;
@@ -182,7 +181,6 @@ public class FingerprintAuthenticationClient
handleLockout(authenticated);
if (authenticated) {
mState = STATE_STOPPED;
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
if (reportBiometricAuthAttempts()) {
mAuthenticationStateListeners.onAuthenticationSucceeded(
@@ -223,7 +221,6 @@ public class FingerprintAuthenticationClient
// Send the error, but do not invoke the FinishCallback yet. Since lockout is not
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationError(
new AuthenticationErrorInfo.Builder(BiometricSourceType.FINGERPRINT,
@@ -275,7 +272,6 @@ public class FingerprintAuthenticationClient
BiometricNotificationUtils.showBadCalibrationNotification(getContext());
}
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo
.Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build()
@@ -284,7 +280,6 @@ public class FingerprintAuthenticationClient
@Override
protected void startHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.show(getSensorId(), getRequestReason(), this);
mAuthenticationStateListeners.onAuthenticationStarted(new AuthenticationStartedInfo
.Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build()
@@ -331,12 +326,6 @@ public class FingerprintAuthenticationClient
if (session.hasContextMethods()) {
try {
session.getSession().onContextChanged(ctx);
- // TODO(b/317414324): Deprecate setIgnoreDisplayTouches
- if (ctx.operationState != null && ctx.operationState.getTag()
- == OperationState.fingerprintOperationState) {
- session.getSession().setIgnoreDisplayTouches(ctx.operationState
- .getFingerprintOperationState().isHardwareIgnoringTouches);
- }
} catch (RemoteException e) {
Slog.e(TAG, "Unable to notify context changed", e);
}
@@ -353,7 +342,6 @@ public class FingerprintAuthenticationClient
@Override
protected void stopHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo
.Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build()
@@ -415,6 +403,15 @@ public class FingerprintAuthenticationClient
}
@Override
+ public void setIgnoreDisplayTouches(boolean ignoreTouches) {
+ try {
+ getFreshDaemon().getSession().setIgnoreDisplayTouches(ignoreTouches);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ @Override
public boolean isPointerDown() {
return mIsPointerDown;
}
@@ -457,7 +454,6 @@ public class FingerprintAuthenticationClient
Slog.e(TAG, "Remote exception", e);
}
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo
.Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build()
@@ -492,7 +488,6 @@ public class FingerprintAuthenticationClient
Slog.e(TAG, "Remote exception", e);
}
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo
.Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build()
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 36af5dba909f..fb48053913cf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -87,7 +87,6 @@ public class FingerprintDetectClient extends AcquisitionClient<AidlSession>
@Override
protected void stopHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(
new AuthenticationStoppedInfo.Builder(BiometricSourceType.FINGERPRINT,
@@ -107,7 +106,6 @@ public class FingerprintDetectClient extends AcquisitionClient<AidlSession>
@Override
protected void startHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.show(getSensorId(), BiometricRequestConstants.REASON_AUTH_KEYGUARD,
this);
mAuthenticationStateListeners.onAuthenticationStarted(
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 3a72d7e9a91a..993a68fd6ff8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -150,7 +150,6 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
controller -> controller.onEnrollmentProgress(getSensorId(), remaining));
if (remaining == 0) {
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(
new AuthenticationStoppedInfo.Builder(
@@ -211,7 +210,6 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
);
super.onError(errorCode, vendorCode);
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(
new AuthenticationStoppedInfo.Builder(BiometricSourceType.FINGERPRINT,
@@ -227,7 +225,6 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
@Override
protected void startHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.show(getSensorId(),
getRequestReasonFromFingerprintEnrollReason(mEnrollReason), this);
mAuthenticationStateListeners.onAuthenticationStarted(new AuthenticationStartedInfo
@@ -277,7 +274,6 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
@Override
protected void stopHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo
.Builder(BiometricSourceType.FINGERPRINT,
@@ -359,5 +355,14 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
}
@Override
+ public void setIgnoreDisplayTouches(boolean ignoreTouches) {
+ try {
+ getFreshDaemon().getSession().setIgnoreDisplayTouches(ignoreTouches);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to send setIgnoreDisplayTouches", e);
+ }
+ }
+
+ @Override
public void onPowerPressed() {}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 1bddb83b1441..12baf00c1c4a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -790,6 +790,19 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
}
@Override
+ public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches) {
+ mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(
+ requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(),
+ "setIgnoreDisplayTouches received during client: " + client);
+ return;
+ }
+ ((Udfps) client).setIgnoreDisplayTouches(ignoreTouches);
+ });
+ }
+
+ @Override
public void onPowerPressed() {
for (int i = 0; i < mFingerprintSensors.size(); i++) {
final Sensor sensor = mFingerprintSensors.valueAt(i);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 7cd9144be77b..6694ebbe461a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1485,6 +1485,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|| !mAutomaticBrightnessStrategy.shouldUseAutoBrightness())) {
rawBrightnessState = getDozeBrightnessForOffload();
brightnessState = clampScreenBrightness(rawBrightnessState);
+ updateScreenBrightnessSetting = false;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_MANUAL);
mTempBrightnessEvent.setFlags(
mTempBrightnessEvent.getFlags() | BrightnessEvent.FLAG_DOZE_SCALE);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 0f9c3440923b..49888db98755 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -597,6 +597,12 @@ public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@Constants.HandleMessageResult
protected int handleReportPhysicalAddress(HdmiCecMessage message) {
super.handleReportPhysicalAddress(message);
+ // Ignore <Report Physical Address> while DeviceDiscoveryAction is in progress to avoid
+ // starting a NewDeviceAction which might interfere in creating the list of known devices.
+ if (hasAction(DeviceDiscoveryAction.class)) {
+ return Constants.HANDLED;
+ }
+
int path = HdmiUtils.twoBytesToInt(message.getParams());
int address = message.getSource();
int type = message.getParams()[2];
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bef984bdcbf7..1f46af8b741d 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3364,6 +3364,10 @@ public class InputManagerService extends IInputManager.Stub
mPointerIconCache.setPointerFillStyle(fillStyle);
}
+ void setPointerStrokeStyle(@PointerIcon.PointerIconVectorStyleStroke int strokeStyle) {
+ mPointerIconCache.setPointerStrokeStyle(strokeStyle);
+ }
+
void setPointerScale(float scale) {
mPointerIconCache.setPointerScale(scale);
}
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 593b0917efc7..000f3122f05a 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -18,6 +18,7 @@ package com.android.server.input;
import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
+import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
import static android.view.flags.Flags.enableVectorCursorA11ySettings;
import static com.android.input.flags.Flags.rateLimitUserActivityPokeInDispatcher;
@@ -103,6 +104,8 @@ class InputSettingsObserver extends ContentObserver {
(reason) -> updateStylusPointerIconEnabled()),
Map.entry(Settings.System.getUriFor(Settings.System.POINTER_FILL_STYLE),
(reason) -> updatePointerFillStyleFromSettings()),
+ Map.entry(Settings.System.getUriFor(Settings.System.POINTER_STROKE_STYLE),
+ (reason) -> updatePointerStrokeStyleFromSettings()),
Map.entry(Settings.System.getUriFor(Settings.System.POINTER_SCALE),
(reason) -> updatePointerScaleFromSettings()));
}
@@ -281,6 +284,17 @@ class InputSettingsObserver extends ContentObserver {
mService.setPointerFillStyle(pointerFillStyle);
}
+ private void updatePointerStrokeStyleFromSettings() {
+ if (!enableVectorCursorA11ySettings()) {
+ return;
+ }
+ final int pointerStrokeStyle = Settings.System.getIntForUser(
+ mContext.getContentResolver(), Settings.System.POINTER_STROKE_STYLE,
+ POINTER_ICON_VECTOR_STYLE_STROKE_WHITE,
+ UserHandle.USER_CURRENT);
+ mService.setPointerStrokeStyle(pointerStrokeStyle);
+ }
+
private void updatePointerScaleFromSettings() {
if (!enableVectorCursorA11ySettings()) {
return;
diff --git a/services/core/java/com/android/server/input/PointerIconCache.java b/services/core/java/com/android/server/input/PointerIconCache.java
index 44622d80da0e..297cd68d5d3d 100644
--- a/services/core/java/com/android/server/input/PointerIconCache.java
+++ b/services/core/java/com/android/server/input/PointerIconCache.java
@@ -18,6 +18,7 @@ package com.android.server.input;
import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
+import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
import android.annotation.NonNull;
import android.content.Context;
@@ -65,6 +66,9 @@ final class PointerIconCache {
private @PointerIcon.PointerIconVectorStyleFill int mPointerIconFillStyle =
POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
@GuardedBy("mLoadedPointerIconsByDisplayAndType")
+ private @PointerIcon.PointerIconVectorStyleStroke int mPointerIconStrokeStyle =
+ POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
+ @GuardedBy("mLoadedPointerIconsByDisplayAndType")
private float mPointerIconScale = DEFAULT_POINTER_SCALE;
private final DisplayManager.DisplayListener mDisplayListener =
@@ -120,6 +124,11 @@ final class PointerIconCache {
mUiThreadHandler.post(() -> handleSetPointerFillStyle(fillStyle));
}
+ /** Set the stroke style for vector pointer icons. */
+ public void setPointerStrokeStyle(@PointerIcon.PointerIconVectorStyleStroke int strokeStyle) {
+ mUiThreadHandler.post(() -> handleSetPointerStrokeStyle(strokeStyle));
+ }
+
/** Set the scale for vector pointer icons. */
public void setPointerScale(float scale) {
mUiThreadHandler.post(() -> handleSetPointerScale(scale));
@@ -144,6 +153,8 @@ final class PointerIconCache {
theme.setTo(context.getTheme());
theme.applyStyle(PointerIcon.vectorFillStyleToResource(mPointerIconFillStyle),
/* force= */ true);
+ theme.applyStyle(PointerIcon.vectorStrokeStyleToResource(mPointerIconStrokeStyle),
+ /* force= */ true);
icon = PointerIcon.getLoadedSystemIcon(new ContextThemeWrapper(context, theme),
type, mUseLargePointerIcons, mPointerIconScale);
iconsByType.put(type, icon);
@@ -224,6 +235,20 @@ final class PointerIconCache {
}
@android.annotation.UiThread
+ private void handleSetPointerStrokeStyle(
+ @PointerIcon.PointerIconVectorStyleStroke int strokeStyle) {
+ synchronized (mLoadedPointerIconsByDisplayAndType) {
+ if (mPointerIconStrokeStyle == strokeStyle) {
+ return;
+ }
+ mPointerIconStrokeStyle = strokeStyle;
+ // Clear all cached icons on all displays.
+ mLoadedPointerIconsByDisplayAndType.clear();
+ }
+ mNative.reloadPointerIcons();
+ }
+
+ @android.annotation.UiThread
private void handleSetPointerScale(float scale) {
synchronized (mLoadedPointerIconsByDisplayAndType) {
if (mPointerIconScale == scale) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1dfdc553641e..fbb6ccf63748 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -195,6 +195,7 @@ import java.lang.annotation.Target;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -298,22 +299,21 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private final String[] mNonPreemptibleInputMethods;
/**
- * See {@link #shouldEnableExperimentalConcurrentMultiUserMode(Context)} about when set to be
- * {@code true}.
+ * See {@link #shouldEnableConcurrentMultiUserMode(Context)} about when set to be {@code true}.
*/
@SharedByAllUsersField
- private final boolean mExperimentalConcurrentMultiUserModeEnabled;
+ private final boolean mConcurrentMultiUserModeEnabled;
/**
- * Returns {@code true} if experimental concurrent multi-user mode is enabled.
+ * Returns {@code true} if the 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.
+ * @return {@code true} if the concurrent multi-user mode is enabled.
*/
- static boolean shouldEnableExperimentalConcurrentMultiUserMode(@NonNull Context context) {
+ static boolean shouldEnableConcurrentMultiUserMode(@NonNull Context context) {
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
&& UserManager.isVisibleBackgroundUsersEnabled()
&& context.getResources().getBoolean(android.R.bool.config_perDisplayFocusEnabled)
@@ -330,7 +330,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@UserIdInt
@BinderThread
private int resolveImeUserIdLocked(@UserIdInt int callingProcessUserId) {
- return mExperimentalConcurrentMultiUserModeEnabled ? callingProcessUserId : mCurrentUserId;
+ return mConcurrentMultiUserModeEnabled ? callingProcessUserId : mCurrentUserId;
}
final Context mContext;
@@ -571,10 +571,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private final ImeTrackerService mImeTrackerService;
class SettingsObserver extends ContentObserver {
- int mUserId;
- boolean mRegistered = false;
- @NonNull
- String mLastEnabled = "";
/**
* <em>This constructor must be called within the lock.</em>
@@ -583,37 +579,29 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
super(handler);
}
- @GuardedBy("ImfLock.class")
- public void registerContentObserverLocked(@UserIdInt int userId) {
- if (mRegistered && mUserId == userId) {
- return;
- }
+ void registerContentObserverForAllUsers() {
ContentResolver resolver = mContext.getContentResolver();
- if (mRegistered) {
- mContext.getContentResolver().unregisterContentObserver(this);
- mRegistered = false;
- }
- if (mUserId != userId) {
- mLastEnabled = "";
- mUserId = userId;
- }
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.DEFAULT_INPUT_METHOD), false, this, userId);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ENABLED_INPUT_METHODS), false, this, userId);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- STYLUS_HANDWRITING_ENABLED), false, this);
- mRegistered = true;
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ Settings.Secure.DEFAULT_INPUT_METHOD), false, this, UserHandle.ALL);
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ Settings.Secure.ENABLED_INPUT_METHODS), false, this, UserHandle.ALL);
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, UserHandle.ALL);
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, UserHandle.ALL);
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, UserHandle.ALL);
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ STYLUS_HANDWRITING_ENABLED), false, this, UserHandle.ALL);
}
@Override
- public void onChange(boolean selfChange, Uri uri) {
+ public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, int flags,
+ @UserIdInt int userId) {
+ uris.forEach(uri -> onChangeInternal(uri, userId));
+ }
+
+ private void onChangeInternal(@NonNull Uri uri, @UserIdInt int userId) {
final Uri showImeUri = Settings.Secure.getUriFor(
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
@@ -621,23 +609,27 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final Uri stylusHandwritingEnabledUri = Settings.Secure.getUriFor(
STYLUS_HANDWRITING_ENABLED);
synchronized (ImfLock.class) {
+ if (!mConcurrentMultiUserModeEnabled && mCurrentUserId != userId) {
+ return;
+ }
+
if (showImeUri.equals(uri)) {
mMenuController.updateKeyboardFromSettingsLocked();
} else if (accessibilityRequestingNoImeUri.equals(uri)) {
final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, userId);
mVisibilityStateComputer.getImePolicy().setA11yRequestNoSoftKeyboard(
accessibilitySoftKeyboardSetting);
- final var userData = getUserData(mUserId);
+ final var userData = getUserData(userId);
if (mVisibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) {
hideCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
0 /* flags */, SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE,
- mUserId);
- } else if (isShowRequestedForCurrentWindow(mUserId)) {
+ userId);
+ } else if (isShowRequestedForCurrentWindow(userId)) {
showCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
InputMethodManager.SHOW_IMPLICIT,
- SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE, mUserId);
+ SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE, userId);
}
} else if (stylusHandwritingEnabledUri.equals(uri)) {
InputMethodManager.invalidateLocalStylusHandwritingAvailabilityCaches();
@@ -645,22 +637,17 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
.invalidateLocalConnectionlessStylusHandwritingAvailabilityCaches();
} else {
boolean enabledChanged = false;
- String newEnabled = InputMethodSettingsRepository.get(mUserId)
+ String newEnabled = InputMethodSettingsRepository.get(userId)
.getEnabledInputMethodsStr();
- if (!mLastEnabled.equals(newEnabled)) {
- mLastEnabled = newEnabled;
+ final var userData = getUserData(userId);
+ if (!userData.mLastEnabledInputMethodsStr.equals(newEnabled)) {
+ userData.mLastEnabledInputMethodsStr = newEnabled;
enabledChanged = true;
}
- updateInputMethodsFromSettingsLocked(enabledChanged, mUserId);
+ updateInputMethodsFromSettingsLocked(enabledChanged, userId);
}
}
}
-
- @Override
- public String toString() {
- return "SettingsObserver{mUserId=" + mUserId + " mRegistered=" + mRegistered
- + " mLastEnabled=" + mLastEnabled + "}";
- }
}
/**
@@ -973,7 +960,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
public Lifecycle(Context context) {
this(context, new InputMethodManagerService(context,
- shouldEnableExperimentalConcurrentMultiUserMode(context)));
+ shouldEnableConcurrentMultiUserMode(context)));
}
public Lifecycle(
@@ -1003,7 +990,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
// Called on ActivityManager thread.
synchronized (ImfLock.class) {
- if (mService.mExperimentalConcurrentMultiUserModeEnabled) {
+ if (mService.mConcurrentMultiUserModeEnabled) {
// In concurrent multi-user mode, we in general do not rely on the concept of
// current user.
return;
@@ -1037,9 +1024,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
SecureSettingsWrapper.onUserStarting(userId);
synchronized (ImfLock.class) {
mService.getUserData(userId);
- if (mService.mExperimentalConcurrentMultiUserModeEnabled) {
+ if (mService.mConcurrentMultiUserModeEnabled) {
if (mService.mCurrentUserId != userId && mService.mSystemReady) {
- mService.experimentalInitializeVisibleBackgroundUserLocked(userId);
+ mService.initializeVisibleBackgroundUserLocked(userId);
}
}
}
@@ -1062,8 +1049,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// We need to rebuild IMEs.
postInputMethodSettingUpdatedLocked(false /* resetDefaultEnabledIme */, userId);
updateInputMethodsFromSettingsLocked(true /* enabledChanged */, userId);
- } else if (mExperimentalConcurrentMultiUserModeEnabled) {
- experimentalInitializeVisibleBackgroundUserLocked(userId);
+ } else if (mConcurrentMultiUserModeEnabled) {
+ initializeVisibleBackgroundUserLocked(userId);
}
}
}
@@ -1090,20 +1077,19 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
public InputMethodManagerService(Context context,
- boolean experimentalConcurrentMultiUserModeEnabled) {
- this(context, experimentalConcurrentMultiUserModeEnabled, null, null, null);
+ boolean concurrentMultiUserModeEnabled) {
+ this(context, concurrentMultiUserModeEnabled, null, null, null);
}
@VisibleForTesting
InputMethodManagerService(
Context context,
- boolean experimentalConcurrentMultiUserModeEnabled,
+ boolean concurrentMultiUserModeEnabled,
@Nullable ServiceThread serviceThreadForTesting,
@Nullable ServiceThread ioThreadForTesting,
@Nullable IntFunction<InputMethodBindingController> bindingControllerForTesting) {
synchronized (ImfLock.class) {
- mExperimentalConcurrentMultiUserModeEnabled =
- experimentalConcurrentMultiUserModeEnabled;
+ mConcurrentMultiUserModeEnabled = concurrentMultiUserModeEnabled;
mContext = context;
mRes = context.getResources();
SecureSettingsWrapper.onStart(mContext);
@@ -1307,11 +1293,12 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
maybeInitImeNavbarConfigLocked(newUserId);
- // ContentObserver should be registered again when the user is changed
- mSettingsObserver.registerContentObserverLocked(newUserId);
+ final var newUserData = getUserData(newUserId);
+
+ // TODO(b/342027196): Double check if we need to always reset upon user switching.
+ newUserData.mLastEnabledInputMethodsStr = "";
mCurrentUserId = newUserId;
- final var newUserData = getUserData(newUserId);
final String defaultImiId = SecureSettingsWrapper.getString(
Settings.Secure.DEFAULT_INPUT_METHOD, null, newUserId);
@@ -1402,7 +1389,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}, "Lazily initialize IMMS#mImeDrawsImeNavBarRes");
mMyPackageMonitor.register(mContext, UserHandle.ALL, mIoHandler);
- mSettingsObserver.registerContentObserverLocked(currentUserId);
+ mSettingsObserver.registerContentObserverForAllUsers();
final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -1428,10 +1415,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
AdditionalSubtypeMapRepository::startWriterThread,
"Start AdditionalSubtypeMapRepository's writer thread");
- if (mExperimentalConcurrentMultiUserModeEnabled) {
+ if (mConcurrentMultiUserModeEnabled) {
for (int userId : mUserManagerInternal.getUserIds()) {
if (userId != mCurrentUserId) {
- experimentalInitializeVisibleBackgroundUserLocked(userId);
+ initializeVisibleBackgroundUserLocked(userId);
}
}
}
@@ -2538,7 +2525,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@SuppressWarnings("GuardedBy") Consumer<ClientState> clearClientSession = c -> {
// TODO(b/305849394): Figure out what we should do for single user IME mode.
final boolean shouldClearClientSession =
- !mExperimentalConcurrentMultiUserModeEnabled
+ !mConcurrentMultiUserModeEnabled
|| UserHandle.getUserId(c.mUid) == userId;
if (shouldClearClientSession) {
clearClientSessionLocked(c);
@@ -2840,27 +2827,25 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
/**
- * This is an experimental implementation used when and only when
- * {@link #mExperimentalConcurrentMultiUserModeEnabled}.
+ * This initialization logic is used when and only when {@link #mConcurrentMultiUserModeEnabled}
+ * is set to {@code true}.
*
- * <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
+ * <p>There remain several yet-to-be-implemented features. For the canonical and desired
+ * behaviors always refer to single-user code paths such as
* {@link #updateInputMethodsFromSettingsLocked(boolean, int)}.</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 InputMethodBindingController#getDeviceIdToShowIme()} is ignored.</li>
- * <li>{@link #mPreventImeStartupUnlessTextEditor} is ignored.</li>
* <li>and so on.</li>
* </ul>
*/
@GuardedBy("ImfLock.class")
- void experimentalInitializeVisibleBackgroundUserLocked(@UserIdInt int userId) {
+ void initializeVisibleBackgroundUserLocked(@UserIdInt int userId) {
final var settings = InputMethodSettingsRepository.get(userId);
// Until we figure out what makes most sense, we enable all the pre-installed IMEs in
@@ -2868,7 +2853,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
String enabledImeIdsStr = settings.getEnabledInputMethodsStr();
for (var imi : settings.getMethodList()) {
if (!imi.isSystem()) {
- return;
+ continue;
}
enabledImeIdsStr = InputMethodUtils.concatEnabledImeIds(enabledImeIdsStr, imi.getId());
}
@@ -2881,19 +2866,18 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
if (TextUtils.isEmpty(id)) {
final InputMethodInfo imi = InputMethodInfoUtils.getMostApplicableDefaultIME(
settings.getEnabledInputMethodList());
- if (imi == null) {
- return;
+ if (imi != null) {
+ id = imi.getId();
+ settings.putSelectedInputMethod(id);
}
- id = imi.getId();
- settings.putSelectedInputMethod(id);
}
+ final var bindingController = getInputMethodBindingController(userId);
+ bindingController.setSelectedMethodId(id);
+ // Also re-initialize controllers.
final var userData = getUserData(userId);
userData.mSwitchingController.resetCircularListLocked(mContext, settings);
userData.mHardwareKeyboardShortcutController.update(settings);
-
- final var bindingController = getInputMethodBindingController(userId);
- bindingController.setSelectedMethodId(id);
}
@GuardedBy("ImfLock.class")
@@ -3701,8 +3685,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final long ident = Binder.clearCallingIdentity();
try {
// Verify if IMMS is in the process of switching user.
- if (!mExperimentalConcurrentMultiUserModeEnabled
- && mUserSwitchHandlerTask != null) {
+ if (!mConcurrentMultiUserModeEnabled && mUserSwitchHandlerTask != null) {
// There is already an on-going pending user switch task.
final int nextUserId = mUserSwitchHandlerTask.mToUserId;
if (userId == nextUserId) {
@@ -3757,7 +3740,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
// Verify if caller is a background user.
- if (!mExperimentalConcurrentMultiUserModeEnabled && userId != mCurrentUserId) {
+ if (!mConcurrentMultiUserModeEnabled && userId != mCurrentUserId) {
if (ArrayUtils.contains(
mUserManagerInternal.getProfileIds(mCurrentUserId, false),
userId)) {
@@ -4269,9 +4252,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
if (currentUser) {
// To avoid unnecessary "updateInputMethodsFromSettingsLocked" from happening.
- if (mSettingsObserver != null) {
- mSettingsObserver.mLastEnabled = settings.getEnabledInputMethodsStr();
- }
+ final var userData = getUserData(userId);
+ userData.mLastEnabledInputMethodsStr = settings.getEnabledInputMethodsStr();
updateInputMethodsFromSettingsLocked(false /* enabledChanged */, userId);
}
}
@@ -5539,7 +5521,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@GuardedBy("ImfLock.class")
private boolean switchToInputMethodLocked(String imeId, @UserIdInt int userId) {
final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
- if (mExperimentalConcurrentMultiUserModeEnabled || userId == mCurrentUserId) {
+ if (mConcurrentMultiUserModeEnabled || userId == mCurrentUserId) {
if (!settings.getMethodMap().containsKey(imeId)
|| !settings.getEnabledInputMethodList()
.contains(settings.getMethodMap().get(imeId))) {
@@ -6110,6 +6092,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
p.println(" inFullscreenMode=" + u.mInFullscreenMode);
p.println(" switchingController:");
u.mSwitchingController.dump(p, " ");
+ p.println(" mLastEnabledInputMethodsStr="
+ + u.mLastEnabledInputMethodsStr);
};
mUserDataRepository.forAllUserData(userDataDump);
@@ -6123,11 +6107,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mVisibilityStateComputer.dump(pw, " ");
p.println(" mInFullscreenMode=" + userData.mInFullscreenMode);
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
- p.println(" mExperimentalConcurrentMultiUserModeEnabled="
- + mExperimentalConcurrentMultiUserModeEnabled);
+ p.println(" mConcurrentMultiUserModeEnabled=" + mConcurrentMultiUserModeEnabled);
p.println(" ENABLE_HIDE_IME_CAPTION_BAR="
+ InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR);
- p.println(" mSettingsObserver=" + mSettingsObserver);
p.println(" mStylusIds=" + (mStylusIds != null
? Arrays.toString(mStylusIds.toArray()) : ""));
diff --git a/services/core/java/com/android/server/inputmethod/UserDataRepository.java b/services/core/java/com/android/server/inputmethod/UserDataRepository.java
index 48284fb3163c..59411ad71bc0 100644
--- a/services/core/java/com/android/server/inputmethod/UserDataRepository.java
+++ b/services/core/java/com/android/server/inputmethod/UserDataRepository.java
@@ -174,6 +174,13 @@ final class UserDataRepository {
mEnabledAccessibilitySessions = new SparseArray<>();
/**
+ * A per-user cache of {@link InputMethodSettings#getEnabledInputMethodsStr()}.
+ */
+ @GuardedBy("ImfLock.class")
+ @NonNull
+ String mLastEnabledInputMethodsStr = "";
+
+ /**
* Intended to be instantiated only from this file.
*/
private UserData(@UserIdInt int userId,
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
index 7c1a5e113a5e..93ef6f044e1b 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
@@ -56,6 +56,7 @@ final class MediaRoute2ProviderWatcher {
private final PackageManager mPackageManager;
private final ArrayList<MediaRoute2ProviderServiceProxy> mProxies = new ArrayList<>();
+ private final Runnable mScanPackagesRunnable = this::scanPackages;
private boolean mRunning;
MediaRoute2ProviderWatcher(Context context,
@@ -106,7 +107,7 @@ final class MediaRoute2ProviderWatcher {
mRunning = false;
mContext.unregisterReceiver(mScanPackagesReceiver);
- mHandler.removeCallbacks(this::scanPackages);
+ mHandler.removeCallbacks(mScanPackagesRunnable);
// Stop all providers.
for (int i = mProxies.size() - 1; i >= 0; i--) {
@@ -189,8 +190,8 @@ final class MediaRoute2ProviderWatcher {
}
private void postScanPackagesIfNeeded() {
- if (!mHandler.hasCallbacks(this::scanPackages)) {
- mHandler.post(this::scanPackages);
+ if (!mHandler.hasCallbacks(mScanPackagesRunnable)) {
+ mHandler.post(mScanPackagesRunnable);
}
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 173fc5c86dd3..009e9b862b0f 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -4568,7 +4568,7 @@ final class InstallPackageHelper {
PackageManagerException.INTERNAL_ERROR_SYSTEM_OVERLAY_STATIC);
}
} else {
- if ((scanFlags & SCAN_AS_VENDOR) != 0) {
+ if ((scanFlags & (SCAN_AS_VENDOR | SCAN_AS_ODM)) != 0) {
if (pkg.getTargetSdkVersion() < ScanPackageUtils.getVendorPartitionVersion()) {
Slog.w(TAG, "System overlay " + pkg.getPackageName()
+ " targets an SDK below the required SDK level of vendor"
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c0b8034b9a56..2e63cdbf1823 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -186,6 +186,7 @@ import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.telephony.CarrierAppUtils;
+import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.ConcurrentUtils;
@@ -4492,8 +4493,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
void setSystemAppHiddenUntilInstalled(@NonNull Computer snapshot, String packageName,
boolean hidden) {
final int callingUid = Binder.getCallingUid();
- final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
- || callingUid == Process.SYSTEM_UID;
+ final boolean calledFromSystemOrPhone = TelephonyPermissions.isSystemOrPhone(callingUid);
if (!calledFromSystemOrPhone) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
"setSystemAppHiddenUntilInstalled");
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index ff8abf879487..924b36cef79a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -92,6 +92,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.content.InstallLocationUtils;
import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.HexDump;
@@ -356,7 +357,7 @@ public class PackageManagerServiceUtils {
* If not, throws a {@link SecurityException}.
*/
public static void enforceSystemOrPhoneCaller(String methodName, int callingUid) {
- if (callingUid != Process.PHONE_UID && callingUid != Process.SYSTEM_UID) {
+ if (!TelephonyPermissions.isSystemOrPhone(callingUid)) {
throw new SecurityException(
"Cannot call " + methodName + " from UID " + callingUid);
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 4d07ab5cbb30..8be20b0e4904 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1637,10 +1637,12 @@ final class DefaultPermissionGrantPolicy {
private boolean isSystemOrCertificateMatchingPackage(PackageInfo pi, String cert) {
if (cert == null) {
return pi.applicationInfo.isSystemApp();
+ } else if (Objects.equals(cert, "platform")) {
+ return mServiceInternal.isPlatformSigned(pi.packageName);
+ } else {
+ return mContext.getPackageManager().hasSigningCertificate(pi.packageName, HexEncoding.
+ decode(cert.replace(":", "")), PackageManager.CERT_INPUT_SHA256);
}
-
- return mContext.getPackageManager().hasSigningCertificate(pi.packageName, HexEncoding.
- decode(cert.replace(":", "")), PackageManager.CERT_INPUT_SHA256);
}
private static boolean doesPackageSupportRuntimePermissions(PackageInfo pkg) {
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index c85ceac9ea55..4f28e023da92 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -154,12 +154,22 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
}
}
+ Slog.i(TAG, "Checking available remediations for health check failure."
+ + " failedPackage: "
+ + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " failureReason: " + failureReason
+ + " available impact: " + impact);
return impact;
}
@Override
public boolean execute(@Nullable VersionedPackage failedPackage,
@FailureReasons int rollbackReason, int mitigationCount) {
+ Slog.i(TAG, "Executing remediation."
+ + " failedPackage: "
+ + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " rollbackReason: " + rollbackReason
+ + " mitigationCount: " + mitigationCount);
if (Flags.recoverabilityDetection()) {
List<RollbackInfo> availableRollbacks = getAvailableRollbacks();
if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
@@ -503,6 +513,10 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
@FailureReasons int rollbackReason) {
assertInWorkerThread();
+ Slog.i(TAG, "Rolling back package. RollbackId: " + rollback.getRollbackId()
+ + " failedPackage: "
+ + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " rollbackReason: " + rollbackReason);
final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason);
final String failedPackageToLog;
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 2fc183d9113f..bc29b377f540 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -532,7 +532,8 @@ final class VibrationSettings {
return false;
}
- if (Flags.keyboardCategoryEnabled() && mVibrationConfig.hasFixedKeyboardAmplitude()) {
+ if (Flags.keyboardCategoryEnabled()
+ && mVibrationConfig.isKeyboardVibrationSettingsSupported()) {
int category = callerInfo.attrs.getCategory();
if (usage == USAGE_TOUCH && category == CATEGORY_KEYBOARD) {
// Keyboard touch has a different user setting.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 484481b4840b..8be338049435 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -734,6 +734,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
private boolean mOccludesParent;
+ /** Whether the activity have style floating */
+ private boolean mStyleFloating;
+
/**
* Unlike {@link #mOccludesParent} which can be changed at runtime. This is a static attribute
* from the style of activity. Because we don't want {@link WindowContainer#getOrientation()}
@@ -2188,7 +2191,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
realTheme, com.android.internal.R.styleable.Window, mUserId);
if (ent != null) {
- mOccludesParent = !ActivityInfo.isTranslucentOrFloating(ent.array)
+ final boolean styleTranslucent = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+ mStyleFloating = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsFloating, false);
+ mOccludesParent = !(styleTranslucent || mStyleFloating)
// This style is propagated to the main window attributes with
// FLAG_SHOW_WALLPAPER from PhoneWindow#generateLayout.
|| ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
@@ -2197,6 +2204,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mOptOutEdgeToEdge = ent.array.getBoolean(
R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false);
} else {
+ mStyleFloating = false;
mStyleFillsParent = mOccludesParent = true;
noDisplay = false;
mOptOutEdgeToEdge = false;
@@ -3237,6 +3245,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return occludesParent(true /* includingFinishing */);
}
+ boolean isStyleFloating() {
+ return mStyleFloating;
+ }
+
/** Returns true if this activity is not finishing, is opaque and fills the entire space of
* this task. */
boolean occludesParent() {
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index d45ed12e5ef6..14e256f7a815 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -1335,12 +1335,16 @@ class BackNavigationController {
}
// If there is only one adaptor, attach the windowless window to top activity,
// because fixed rotation only applies on activity.
- // Note that embedded activity won't use fixed rotation.
- final Configuration openConfig = mAdaptors.length == 1
+ // Note that embedded activity won't use fixed rotation. Also, there is only one
+ // animation target for closing task.
+ final boolean chooseActivity = mAdaptors.length == 1
+ && (switchType == ACTIVITY_SWITCH || mainActivity.mDisplayContent
+ .isFixedRotationLaunchingApp(mainActivity));
+ final Configuration openConfig = chooseActivity
? mainActivity.getConfiguration() : openTask.getConfiguration();
mRequestedStartingSurfaceId = openTask.mAtmService.mTaskOrganizerController
.addWindowlessStartingSurface(openTask, mainActivity,
- mAdaptors.length == 1 ? mainActivity.getSurfaceControl()
+ chooseActivity ? mainActivity.getSurfaceControl()
: mRemoteAnimationTarget.leash, snapshot, openConfig,
new IWindowlessStartingSurfaceCallback.Stub() {
// Once the starting surface has been created in shell, it will call
diff --git a/services/core/java/com/android/server/wm/DeviceStateController.java b/services/core/java/com/android/server/wm/DeviceStateController.java
index 857e03d71f3f..475a50473780 100644
--- a/services/core/java/com/android/server/wm/DeviceStateController.java
+++ b/services/core/java/com/android/server/wm/DeviceStateController.java
@@ -16,9 +16,19 @@
package com.android.server.wm;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN;
+
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.feature.flags.FeatureFlags;
+import android.hardware.devicestate.feature.flags.FeatureFlagsImpl;
import android.util.ArrayMap;
import android.util.Pair;
@@ -28,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -43,16 +54,16 @@ final class DeviceStateController {
@NonNull
private final WindowManagerGlobalLock mWmLock;
@NonNull
- private final int[] mOpenDeviceStates;
+ private final List<Integer> mOpenDeviceStates;
@NonNull
- private final int[] mHalfFoldedDeviceStates;
+ private final List<Integer> mHalfFoldedDeviceStates;
@NonNull
- private final int[] mFoldedDeviceStates;
+ private final List<Integer> mFoldedDeviceStates;
@NonNull
- private final int[] mRearDisplayDeviceStates;
- private final int mConcurrentDisplayDeviceState;
+ private final List<Integer> mRearDisplayDeviceStates;
+ private final List<Integer> mConcurrentDisplayDeviceStates;
@NonNull
- private final int[] mReverseRotationAroundZAxisStates;
+ private final List<Integer> mReverseRotationAroundZAxisStates;
@GuardedBy("mWmLock")
@NonNull
@VisibleForTesting
@@ -76,18 +87,55 @@ final class DeviceStateController {
DeviceStateController(@NonNull Context context, @NonNull WindowManagerGlobalLock wmLock) {
mWmLock = wmLock;
- mOpenDeviceStates = context.getResources()
- .getIntArray(R.array.config_openDeviceStates);
- mHalfFoldedDeviceStates = context.getResources()
- .getIntArray(R.array.config_halfFoldedDeviceStates);
- mFoldedDeviceStates = context.getResources()
- .getIntArray(R.array.config_foldedDeviceStates);
- mRearDisplayDeviceStates = context.getResources()
- .getIntArray(R.array.config_rearDisplayDeviceStates);
- mConcurrentDisplayDeviceState = context.getResources()
- .getInteger(R.integer.config_deviceStateConcurrentRearDisplay);
- mReverseRotationAroundZAxisStates = context.getResources()
- .getIntArray(R.array.config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis);
+ final FeatureFlags deviceStateManagerFlags = new FeatureFlagsImpl();
+ if (deviceStateManagerFlags.deviceStatePropertyMigration()) {
+ mOpenDeviceStates = new ArrayList<>();
+ mHalfFoldedDeviceStates = new ArrayList<>();
+ mFoldedDeviceStates = new ArrayList<>();
+ mRearDisplayDeviceStates = new ArrayList<>();
+ mConcurrentDisplayDeviceStates = new ArrayList<>();
+
+ final DeviceStateManager deviceStateManager =
+ context.getSystemService(DeviceStateManager.class);
+ final List<android.hardware.devicestate.DeviceState> deviceStates =
+ deviceStateManager.getSupportedDeviceStates();
+
+ for (int i = 0; i < deviceStates.size(); i++) {
+ final android.hardware.devicestate.DeviceState state = deviceStates.get(i);
+ if (state.hasProperty(
+ PROPERTY_FEATURE_REAR_DISPLAY)) {
+ mRearDisplayDeviceStates.add(state.getIdentifier());
+ } else if (state.hasProperty(
+ PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT)) {
+ mConcurrentDisplayDeviceStates.add(state.getIdentifier());
+ } else if (state.hasProperty(
+ PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)) {
+ mFoldedDeviceStates.add(state.getIdentifier());
+ } else if (state.hasProperty(
+ PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)) {
+ if (state.hasProperty(
+ PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN)) {
+ mHalfFoldedDeviceStates.add(state.getIdentifier());
+ } else {
+ mOpenDeviceStates.add(state.getIdentifier());
+ }
+ }
+ }
+ } else {
+ mOpenDeviceStates = copyIntArrayToList(context.getResources()
+ .getIntArray(R.array.config_openDeviceStates));
+ mHalfFoldedDeviceStates = copyIntArrayToList(context.getResources()
+ .getIntArray(R.array.config_halfFoldedDeviceStates));
+ mFoldedDeviceStates = copyIntArrayToList(context.getResources()
+ .getIntArray(R.array.config_foldedDeviceStates));
+ mRearDisplayDeviceStates = copyIntArrayToList(context.getResources()
+ .getIntArray(R.array.config_rearDisplayDeviceStates));
+ mConcurrentDisplayDeviceStates = new ArrayList<>(List.of(context.getResources()
+ .getInteger(R.integer.config_deviceStateConcurrentRearDisplay)));
+ }
+
+ mReverseRotationAroundZAxisStates = copyIntArrayToList(context.getResources().getIntArray(
+ R.array.config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis));
mMatchBuiltInDisplayOrientationToDefaultDisplay = context.getResources()
.getBoolean(R.bool
.config_matchSecondaryInternalDisplaysOrientationToReverseDefaultDisplay);
@@ -145,7 +193,6 @@ final class DeviceStateController {
*/
public void onDeviceStateReceivedByDisplayManager(int state) {
mCurrentState = state;
-
final DeviceState deviceState;
if (ArrayUtils.contains(mHalfFoldedDeviceStates, state)) {
deviceState = DeviceState.HALF_FOLDED;
@@ -155,9 +202,10 @@ final class DeviceStateController {
deviceState = DeviceState.REAR;
} else if (ArrayUtils.contains(mOpenDeviceStates, state)) {
deviceState = DeviceState.OPEN;
- } else if (state == mConcurrentDisplayDeviceState) {
+ } else if (ArrayUtils.contains(mConcurrentDisplayDeviceStates, state)) {
deviceState = DeviceState.CONCURRENT;
} else {
+
deviceState = DeviceState.UNKNOWN;
}
@@ -190,4 +238,16 @@ final class DeviceStateController {
}
return entries;
}
+
+ @NonNull
+ private List<Integer> copyIntArrayToList(@Nullable int[] values) {
+ if (values == null) {
+ return Collections.emptyList();
+ }
+ final List<Integer> valueList = new ArrayList<>();
+ for (int i = 0; i < values.length; i++) {
+ valueList.add(values[i]);
+ }
+ return valueList;
+ }
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7206b36a41d5..33a649be43d0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3411,6 +3411,7 @@ class Task extends TaskFragment {
info.isVisibleRequested = isVisibleRequested();
info.isSleeping = shouldSleepActivities();
info.isTopActivityTransparent = top != null && !top.fillsParent();
+ info.isTopActivityStyleFloating = top != null && top.isStyleFloating();
appCompatTaskInfo.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
appCompatTaskInfo.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
appCompatTaskInfo.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fec1175785ea..de73e6cfad12 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -28,6 +28,7 @@ import static android.graphics.GraphicsProtos.dumpPointProto;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.PowerManager.DRAW_WAKE_LOCK;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.util.SequenceUtils.getNextSeq;
import static android.view.SurfaceControl.Transaction;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
@@ -96,7 +97,6 @@ import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
-import static android.util.SequenceUtils.getNextSeq;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
@@ -249,8 +249,8 @@ import android.window.OnBackInvokedCallbackInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.KeyInterceptionInfo;
-import com.android.internal.protolog.common.LogLevel;
import com.android.internal.protolog.ProtoLog;
+import com.android.internal.protolog.common.LogLevel;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.policy.WindowManagerPolicy;
@@ -1976,8 +1976,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
boolean isReadyForDisplay() {
final boolean parentAndClientVisible = !isParentWindowHidden()
- && mViewVisibility == View.VISIBLE && mToken.isVisible();
- return mHasSurface && isVisibleByPolicy() && !mDestroying
+ && mViewVisibility == View.VISIBLE;
+ return mHasSurface && isVisibleByPolicy() && !mDestroying && mToken.isVisible()
&& (parentAndClientVisible || isAnimating(TRANSITION | PARENTS));
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 7a710dc51004..7649a4e84bc3 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -193,7 +193,7 @@ cc_defaults {
"android.hardware.thermal-V2-ndk",
"android.hardware.tv.input@1.0",
"android.hardware.tv.input-V2-ndk",
- "android.hardware.vibrator-V2-cpp",
+ "android.hardware.vibrator-V2-ndk",
"android.hardware.vibrator@1.0",
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index 4be21d872383..2804a10c317f 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -16,24 +16,21 @@
#define LOG_TAG "VibratorController"
+#include <aidl/android/hardware/vibrator/IVibrator.h>
#include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <android/hardware/vibrator/IVibrator.h>
-
#include <nativehelper/JNIHelp.h>
-#include "android_runtime/AndroidRuntime.h"
-#include "core_jni_helpers.h"
-#include "jni.h"
-
#include <utils/Log.h>
#include <utils/misc.h>
-
#include <vibratorservice/VibratorHalController.h>
+#include "android_runtime/AndroidRuntime.h"
#include "com_android_server_vibrator_VibratorManagerService.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
namespace V1_0 = android::hardware::vibrator::V1_0;
namespace V1_3 = android::hardware::vibrator::V1_3;
-namespace aidl = android::hardware::vibrator;
+namespace Aidl = aidl::android::hardware::vibrator;
namespace android {
@@ -67,29 +64,29 @@ static struct {
} sRampClassInfo;
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
- static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
+ static_cast<uint8_t>(Aidl::EffectStrength::LIGHT));
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
- static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
+ static_cast<uint8_t>(Aidl::EffectStrength::MEDIUM));
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
- static_cast<uint8_t>(aidl::EffectStrength::STRONG));
+ static_cast<uint8_t>(Aidl::EffectStrength::STRONG));
static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
- static_cast<uint8_t>(aidl::Effect::CLICK));
+ static_cast<uint8_t>(Aidl::Effect::CLICK));
static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
- static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == static_cast<uint8_t>(aidl::Effect::TICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == static_cast<uint8_t>(aidl::Effect::THUD));
-static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == static_cast<uint8_t>(aidl::Effect::POP));
+ static_cast<uint8_t>(Aidl::Effect::DOUBLE_CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == static_cast<uint8_t>(Aidl::Effect::TICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == static_cast<uint8_t>(Aidl::Effect::THUD));
+static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == static_cast<uint8_t>(Aidl::Effect::POP));
static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
- static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
+ static_cast<uint8_t>(Aidl::Effect::HEAVY_CLICK));
static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
- static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
+ static_cast<uint8_t>(Aidl::Effect::RINGTONE_1));
static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
- static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
+ static_cast<uint8_t>(Aidl::Effect::RINGTONE_2));
static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
- static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
+ static_cast<uint8_t>(Aidl::Effect::RINGTONE_15));
static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
- static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
+ static_cast<uint8_t>(Aidl::Effect::TEXTURE_TICK));
static std::shared_ptr<vibrator::HalController> findVibrator(int32_t vibratorId) {
vibrator::ManagerHalController* manager =
@@ -155,15 +152,15 @@ private:
std::atomic<int64_t> mCallbackId;
};
-static aidl::BrakingPwle brakingPwle(aidl::Braking braking, int32_t duration) {
- aidl::BrakingPwle pwle;
+static Aidl::BrakingPwle brakingPwle(Aidl::Braking braking, int32_t duration) {
+ Aidl::BrakingPwle pwle;
pwle.braking = braking;
pwle.duration = duration;
return pwle;
}
-static aidl::ActivePwle activePwleFromJavaPrimitive(JNIEnv* env, jobject ramp) {
- aidl::ActivePwle pwle;
+static Aidl::ActivePwle activePwleFromJavaPrimitive(JNIEnv* env, jobject ramp) {
+ Aidl::ActivePwle pwle;
pwle.startAmplitude =
static_cast<float>(env->GetFloatField(ramp, sRampClassInfo.startAmplitude));
pwle.endAmplitude = static_cast<float>(env->GetFloatField(ramp, sRampClassInfo.endAmplitude));
@@ -175,20 +172,20 @@ static aidl::ActivePwle activePwleFromJavaPrimitive(JNIEnv* env, jobject ramp) {
}
/* Return true if braking is not NONE and the active PWLE starts and ends with zero amplitude. */
-static bool shouldBeReplacedWithBraking(aidl::ActivePwle activePwle, aidl::Braking braking) {
- return (braking != aidl::Braking::NONE) && (activePwle.startAmplitude == 0) &&
+static bool shouldBeReplacedWithBraking(Aidl::ActivePwle activePwle, Aidl::Braking braking) {
+ return (braking != Aidl::Braking::NONE) && (activePwle.startAmplitude == 0) &&
(activePwle.endAmplitude == 0);
}
/* Return true if braking is not NONE and the active PWLE only ends with zero amplitude. */
-static bool shouldAddLastBraking(aidl::ActivePwle lastActivePwle, aidl::Braking braking) {
- return (braking != aidl::Braking::NONE) && (lastActivePwle.startAmplitude > 0) &&
+static bool shouldAddLastBraking(Aidl::ActivePwle lastActivePwle, Aidl::Braking braking) {
+ return (braking != Aidl::Braking::NONE) && (lastActivePwle.startAmplitude > 0) &&
(lastActivePwle.endAmplitude == 0);
}
-static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
- aidl::CompositeEffect effect;
- effect.primitive = static_cast<aidl::CompositePrimitive>(
+static Aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
+ Aidl::CompositeEffect effect;
+ effect.primitive = static_cast<Aidl::CompositePrimitive>(
env->GetIntField(primitive, sPrimitiveClassInfo.id));
effect.scale = static_cast<float>(env->GetFloatField(primitive, sPrimitiveClassInfo.scale));
effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, sPrimitiveClassInfo.delay));
@@ -282,8 +279,8 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong ptr, j
ALOGE("vibratorPerformEffect failed because native wrapper was not initialized");
return -1;
}
- aidl::Effect effectType = static_cast<aidl::Effect>(effect);
- aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
+ Aidl::Effect effectType = static_cast<Aidl::Effect>(effect);
+ Aidl::EffectStrength effectStrength = static_cast<Aidl::EffectStrength>(strength);
auto callback = wrapper->createCallback(vibrationId);
auto performEffectFn = [effectType, effectStrength, &callback](vibrator::HalWrapper* hal) {
return hal->performEffect(effectType, effectStrength, callback);
@@ -300,7 +297,7 @@ static jlong vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlon
return -1;
}
size_t size = env->GetArrayLength(composition);
- std::vector<aidl::CompositeEffect> effects;
+ std::vector<Aidl::CompositeEffect> effects;
for (size_t i = 0; i < size; i++) {
jobject element = env->GetObjectArrayElement(composition, i);
effects.push_back(effectFromJavaPrimitive(env, element));
@@ -321,13 +318,13 @@ static jlong vibratorPerformPwleEffect(JNIEnv* env, jclass /* clazz */, jlong pt
ALOGE("vibratorPerformPwleEffect failed because native wrapper was not initialized");
return -1;
}
- aidl::Braking braking = static_cast<aidl::Braking>(brakingId);
+ Aidl::Braking braking = static_cast<Aidl::Braking>(brakingId);
size_t size = env->GetArrayLength(waveform);
- std::vector<aidl::PrimitivePwle> primitives;
+ std::vector<Aidl::PrimitivePwle> primitives;
std::chrono::milliseconds totalDuration(0);
for (size_t i = 0; i < size; i++) {
jobject element = env->GetObjectArrayElement(waveform, i);
- aidl::ActivePwle activePwle = activePwleFromJavaPrimitive(env, element);
+ Aidl::ActivePwle activePwle = activePwleFromJavaPrimitive(env, element);
if ((i > 0) && shouldBeReplacedWithBraking(activePwle, braking)) {
primitives.push_back(brakingPwle(braking, activePwle.duration));
} else {
@@ -356,8 +353,8 @@ static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong ptr, j
return;
}
auto alwaysOnEnableFn = [id, effect, strength](vibrator::HalWrapper* hal) {
- return hal->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
- static_cast<aidl::EffectStrength>(strength));
+ return hal->alwaysOnEnable(static_cast<int32_t>(id), static_cast<Aidl::Effect>(effect),
+ static_cast<Aidl::EffectStrength>(strength));
};
wrapper->halCall<void>(alwaysOnEnableFn, "alwaysOnEnable");
}
@@ -389,7 +386,7 @@ static jboolean vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr,
static_cast<jlong>(info.capabilities.value()));
}
if (info.supportedEffects.isOk()) {
- std::vector<aidl::Effect> effects = info.supportedEffects.value();
+ std::vector<Aidl::Effect> effects = info.supportedEffects.value();
jintArray supportedEffects = env->NewIntArray(effects.size());
env->SetIntArrayRegion(supportedEffects, 0, effects.size(),
reinterpret_cast<jint*>(effects.data()));
@@ -397,7 +394,7 @@ static jboolean vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr,
sVibratorInfoBuilderClassInfo.setSupportedEffects, supportedEffects);
}
if (info.supportedBraking.isOk()) {
- std::vector<aidl::Braking> braking = info.supportedBraking.value();
+ std::vector<Aidl::Braking> braking = info.supportedBraking.value();
jintArray supportedBraking = env->NewIntArray(braking.size());
env->SetIntArrayRegion(supportedBraking, 0, braking.size(),
reinterpret_cast<jint*>(braking.data()));
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 215cf2c5c85c..791d030a6b63 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2134,14 +2134,20 @@ public final class SystemServer implements Dumpable {
}
t.traceEnd();
- t.traceBegin("StartVpnManagerService");
- try {
- vpnManager = VpnManagerService.create(context);
- ServiceManager.addService(Context.VPN_MANAGEMENT_SERVICE, vpnManager);
- } catch (Throwable e) {
- reportWtf("starting VPN Manager Service", e);
+ if (!isWatch || !android.server.Flags.allowRemovingVpnService()) {
+ t.traceBegin("StartVpnManagerService");
+ try {
+ vpnManager = VpnManagerService.create(context);
+ ServiceManager.addService(Context.VPN_MANAGEMENT_SERVICE, vpnManager);
+ } catch (Throwable e) {
+ reportWtf("starting VPN Manager Service", e);
+ }
+ t.traceEnd();
+ } else {
+ // VPN management currently does not work in Wear, so skip starting the
+ // VPN manager SystemService.
+ Slog.i(TAG, "Not starting VpnManagerService");
}
- t.traceEnd();
t.traceBegin("StartVcnManagementService");
try {
diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig
index e8aa68cf1a63..29f387117073 100644
--- a/services/java/com/android/server/flags.aconfig
+++ b/services/java/com/android/server/flags.aconfig
@@ -21,4 +21,11 @@ flag {
namespace: "wear_frameworks"
description: "Remove WearableSensingManagerService on Wear"
bug: "340929916"
+}
+
+flag {
+ name: "allow_removing_vpn_service"
+ namespace: "wear_frameworks"
+ description: "Allow removing VpnManagerService"
+ bug: "340928692"
} \ No newline at end of file
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 78dbc60dbae0..0b7438cd1b17 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -2687,7 +2687,7 @@ class PermissionService(private val service: AccessCheckingService) :
runtimePermissionChangedUidDevices.getOrPut(uid) { mutableSetOf() } += deviceId
}
- if (permission.hasGids && !wasPermissionGranted && isPermissionGranted) {
+ if (permission.hasGids && (wasPermissionGranted != isPermissionGranted)) {
gidsChangedUids += uid
}
}
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 977a8a05d6f3..64dbc50b8dd2 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -398,14 +398,17 @@ public final class ProfcollectForwardingService extends SystemService {
if (randomNum >= traceFrequency) {
return;
}
- // Wait for 1s before starting tracing.
+ // For a small percentage a traces, we collect the initialization behavior.
+ boolean traceInitialization = ThreadLocalRandom.current().nextInt(10) < 1;
+ int traceDelay = traceInitialization ? 0 : 1000;
+ String traceTag = traceInitialization ? "camera_init" : "camera";
BackgroundThread.get().getThreadHandler().postDelayed(() -> {
try {
- mIProfcollect.trace_once("camera");
+ mIProfcollect.trace_once(traceTag);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
}
- }, 1000);
+ }, traceDelay);
}
}, null);
}
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 80eab112d814..17d9ef9fad34 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -233,7 +233,7 @@ public class InputMethodManagerServiceTestBase {
Process.THREAD_PRIORITY_FOREGROUND,
true /* allowIo */);
mInputMethodManagerService = new InputMethodManagerService(mContext,
- InputMethodManagerService.shouldEnableExperimentalConcurrentMultiUserMode(mContext),
+ InputMethodManagerService.shouldEnableConcurrentMultiUserMode(mContext),
mServiceThread, mIoThread,
unusedUserId -> mMockInputMethodBindingController);
spyOn(mInputMethodManagerService);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index d070aaa93b01..2018e1a3ae62 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1942,7 +1942,7 @@ public final class DisplayPowerControllerTest {
}
@Test
- public void testDozeManualBrightness() {
+ public void testDozeManualBrightness_DpcRefactorDisabled() {
when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
Settings.System.putInt(mContext.getContentResolver(),
@@ -1972,6 +1972,45 @@ public final class DisplayPowerControllerTest {
/* ignoreAnimationLimits= */ anyBoolean());
assertEquals(brightness * DOZE_SCALE_FACTOR, mHolder.dpc.getDozeBrightnessForOffload(),
/* delta= */ 0);
+ // This brightness shouldn't be stored in the setting
+ verify(mHolder.brightnessSetting, never()).setBrightness(brightness * DOZE_SCALE_FACTOR);
+ }
+
+ @Test
+ public void testDozeManualBrightness_DpcRefactorEnabled() {
+ when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
+ when(mDisplayManagerFlagsMock.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+ mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+ float brightness = 0.277f;
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
+ when(mHolder.hbmController.getCurrentBrightnessMax())
+ .thenReturn(PowerManager.BRIGHTNESS_MAX);
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState, initialize
+
+ ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor =
+ ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class);
+ verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture());
+ BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue();
+ listener.onBrightnessChanged(brightness);
+ advanceTime(1); // Send messages, run updatePowerState
+
+ verify(mHolder.animator).animateTo(eq(brightness * DOZE_SCALE_FACTOR),
+ /* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(),
+ /* ignoreAnimationLimits= */ anyBoolean());
+ assertEquals(brightness * DOZE_SCALE_FACTOR, mHolder.dpc.getDozeBrightnessForOffload(),
+ /* delta= */ 0);
+ // This brightness shouldn't be stored in the setting
+ verify(mHolder.brightnessSetting, never()).setBrightness(brightness * DOZE_SCALE_FACTOR);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index ecd799f44552..6ec888cd2e45 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -406,8 +406,6 @@ public class FingerprintAuthenticationClientTest {
mContextInjector.getValue().accept(opContext);
verify(mHal).onContextChanged(same(opContext));
- verify(mHal, times(2)).setIgnoreDisplayTouches(
- opContext.operationState.getFingerprintOperationState().isHardwareIgnoringTouches);
client.stopHalOperation();
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 21364b861ed8..87b52e6194ce 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -2068,7 +2068,6 @@ public class HdmiCecLocalDeviceTvTest {
assertThat(mPowerManager.isInteractive()).isTrue();
}
-
@Test
public void handleStandby_fromNonActiveSource_previousActiveSourceNotSet_Standby() {
HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
@@ -2091,6 +2090,35 @@ public class HdmiCecLocalDeviceTvTest {
.isFalse();
}
+ @Test
+ public void handleReportPhysicalAddress_DeviceDiscoveryActionInProgress_noNewDeviceAction() {
+ mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
+ mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage reportPhysicalAddressFromPlayback1 =
+ HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_PLAYBACK_1, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK);
+ HdmiCecMessage reportPhysicalAddressFromPlayback2 =
+ HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_PLAYBACK_2, 0x2000, HdmiDeviceInfo.DEVICE_PLAYBACK);
+ HdmiCecMessage giveOsdName = HdmiCecMessageBuilder.buildGiveOsdNameCommand(
+ ADDR_TV, ADDR_PLAYBACK_2);
+ // Skip state waiting for <Report Physical Address> for DeviceDiscoveryAction s.t. message
+ // can be dispatched to local device TV.
+ mNativeWrapper.onCecMessage(reportPhysicalAddressFromPlayback1);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.dispatchAll();
+
+ mNativeWrapper.onCecMessage(reportPhysicalAddressFromPlayback2);
+ mTestLooper.dispatchAll();
+
+ // NewDeviceAction did not start and <Give OSD Name> was not sent.
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveOsdName);
+ }
+
protected static class MockTvDevice extends HdmiCecLocalDeviceTv {
MockTvDevice(HdmiControlService service) {
super(service);
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
index 88a94830e98a..60d8964267f1 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -605,7 +605,7 @@ public class VibrationSettingsTest {
public void shouldIgnoreVibration_withKeyboardSettingsOff_shouldIgnoreKeyboardVibration() {
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_MEDIUM);
setUserSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED, 0 /* OFF*/);
- setHasFixedKeyboardAmplitudeIntensity(true);
+ setKeyboardVibrationSettingsSupported(true);
// Keyboard touch ignored.
assertVibrationIgnoredForAttributes(
@@ -630,7 +630,7 @@ public class VibrationSettingsTest {
public void shouldIgnoreVibration_withKeyboardSettingsOn_shouldNotIgnoreKeyboardVibration() {
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED, 1 /* ON */);
- setHasFixedKeyboardAmplitudeIntensity(true);
+ setKeyboardVibrationSettingsSupported(true);
// General touch ignored.
assertVibrationIgnoredForUsage(USAGE_TOUCH, Vibration.Status.IGNORED_FOR_SETTINGS);
@@ -645,10 +645,10 @@ public class VibrationSettingsTest {
@Test
@RequiresFlagsEnabled(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED)
- public void shouldIgnoreVibration_noFixedKeyboardAmplitude_ignoresKeyboardTouchVibration() {
+ public void shouldIgnoreVibration_notSupportKeyboardVibration_ignoresKeyboardTouchVibration() {
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED, 1 /* ON */);
- setHasFixedKeyboardAmplitudeIntensity(false);
+ setKeyboardVibrationSettingsSupported(false);
// General touch ignored.
assertVibrationIgnoredForUsage(USAGE_TOUCH, Vibration.Status.IGNORED_FOR_SETTINGS);
@@ -974,8 +974,8 @@ public class VibrationSettingsTest {
when(mVibrationConfigMock.ignoreVibrationsOnWirelessCharger()).thenReturn(ignore);
}
- private void setHasFixedKeyboardAmplitudeIntensity(boolean hasFixedAmplitude) {
- when(mVibrationConfigMock.hasFixedKeyboardAmplitude()).thenReturn(hasFixedAmplitude);
+ private void setKeyboardVibrationSettingsSupported(boolean supported) {
+ when(mVibrationConfigMock.isKeyboardVibrationSettingsSupported()).thenReturn(supported);
}
private void deleteUserSetting(String settingName) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
index 51255948ed4a..36861fae35da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
@@ -16,6 +16,15 @@
package com.android.server.wm;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN;
+import static android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -24,8 +33,11 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.res.Resources;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
import android.util.Pair;
import androidx.test.filters.SmallTest;
@@ -37,6 +49,8 @@ import com.google.common.util.concurrent.MoreExecutors;
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -79,39 +93,67 @@ public class DeviceStateControllerTests {
@Test
public void testInitialization() {
initialize(true /* supportFold */, true /* supportHalfFolded */);
- mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
+ mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
}
@Test
public void testInitializationWithNoFoldSupport() {
initialize(false /* supportFold */, false /* supportHalfFolded */);
- mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]);
+ mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
// Note that the folded state is ignored.
assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState);
}
@Test
- public void testWithFoldSupported() {
+ @RequiresFlagsDisabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
+ public void testWithFoldSupported_withOverlayConfigValues() {
initialize(true /* supportFold */, false /* supportHalfFolded */);
- mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
+ mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
- mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]);
+ mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
- mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates[0]);
+ mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier());
assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState); // Ignored
}
@Test
- public void testWithHalfFoldSupported() {
+ @RequiresFlagsEnabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
+ public void testWithFoldSupported_withDeviceStateManagerPropertyAPI() {
+ initialize(true /* supportFold */, false /* supportHalfFolded */);
+ mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
+ assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
+ mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
+ assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
+ mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier());
+ assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState); // Ignored
+ }
+
+ @Test
+ @RequiresFlagsDisabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
+ public void testWithHalfFoldSupported_withOverlayConfigValue() {
+ initialize(true /* supportFold */, true /* supportHalfFolded */);
+ mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
+ assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
+ mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
+ assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
+ mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier());
+ assertEquals(DeviceStateController.DeviceState.HALF_FOLDED, mCurrentState);
+ mTarget.onDeviceStateReceivedByDisplayManager(mConcurrentDisplayState.getIdentifier());
+ assertEquals(DeviceStateController.DeviceState.CONCURRENT, mCurrentState);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
+ public void testWithHalfFoldSupported_withDeviceStateManagerPropertyApi() {
initialize(true /* supportFold */, true /* supportHalfFolded */);
- mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
+ mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
- mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]);
+ mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
- mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates[0]);
+ mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier());
assertEquals(DeviceStateController.DeviceState.HALF_FOLDED, mCurrentState);
- mTarget.onDeviceStateReceivedByDisplayManager(mConcurrentDisplayState);
+ mTarget.onDeviceStateReceivedByDisplayManager(mConcurrentDisplayState.getIdentifier());
assertEquals(DeviceStateController.DeviceState.CONCURRENT, mCurrentState);
}
@@ -121,16 +163,18 @@ public class DeviceStateControllerTests {
assertEquals(1, mTarget.mDeviceStateCallbacks.size());
assertTrue(mTarget.mDeviceStateCallbacks.containsKey(mDelegate));
- mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
+ mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
- mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]);
+ mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
// The callback should not receive state change when it is unregistered.
mTarget.unregisterDeviceStateCallback(mDelegate);
assertTrue(mTarget.mDeviceStateCallbacks.isEmpty());
- mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
- assertEquals(DeviceStateController.DeviceState.FOLDED /* unchanged */, mCurrentState);
+
+ mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
+ assertEquals(DeviceStateController.DeviceState.FOLDED /* unchanged */,
+ mCurrentState);
}
@Test
@@ -151,16 +195,50 @@ public class DeviceStateControllerTests {
assertEquals(mExecutor, entries.get(0).second);
}
- private final int[] mFoldedStates = {0};
- private final int[] mOpenDeviceStates = {1};
- private final int[] mHalfFoldedStates = {2};
- private final int[] mRearDisplayStates = {3};
- private final int mConcurrentDisplayState = 4;
+ private final List<DeviceState> mFoldedStates = new ArrayList<>(
+ List.of(new DeviceState(new DeviceState.Configuration.Builder(0,
+ "folded").setSystemProperties(new HashSet<>(
+ List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)))
+ .setPhysicalProperties(new HashSet<>(
+ List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)))
+ .build())));
+ private final List<DeviceState> mOpenDeviceStates = new ArrayList<>(
+ List.of(new DeviceState(new DeviceState.Configuration.Builder(1,
+ "open").setSystemProperties(new HashSet<>(
+ List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)))
+ .setPhysicalProperties(new HashSet<>(
+ List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)))
+ .build())));
+ private final List<DeviceState> mHalfFoldedStates = new ArrayList<>(
+ List.of(new DeviceState(new DeviceState.Configuration.Builder(2,
+ "half_folded").setSystemProperties(new HashSet<>(
+ List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)))
+ .setPhysicalProperties(new HashSet<>(
+ List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN)))
+ .build())));
+ private final List<DeviceState> mRearDisplayStates = new ArrayList<>(
+ List.of(new DeviceState(new DeviceState.Configuration.Builder(3,
+ "rear_display").setSystemProperties(new HashSet<>(
+ List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
+ PROPERTY_FEATURE_REAR_DISPLAY)))
+ .setPhysicalProperties(new HashSet<>(
+ List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)))
+ .build())));
+ private final DeviceState mConcurrentDisplayState = new DeviceState(
+ new DeviceState.Configuration.Builder(4, "concurrent_display")
+ .setSystemProperties(new HashSet<>(List.of(
+ PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
+ PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT)))
+ .setPhysicalProperties(new HashSet<>(List.of(
+ PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)))
+ .build());
private class DeviceStateControllerBuilder {
private boolean mSupportFold = false;
private boolean mSupportHalfFold = false;
+
private Consumer<DeviceStateController.DeviceState> mDelegate;
+ private final List<DeviceState> mDeviceStateList = new ArrayList<>();
DeviceStateControllerBuilder setSupportFold(
boolean supportFold, boolean supportHalfFold) {
@@ -179,13 +257,17 @@ public class DeviceStateControllerTests {
if (enableFold || enableHalfFold) {
when(mMockContext.getResources()
.getIntArray(R.array.config_openDeviceStates))
- .thenReturn(mOpenDeviceStates);
+ .thenReturn(mapDeviceStateListToIdentifierArray(mOpenDeviceStates));
when(mMockContext.getResources()
.getIntArray(R.array.config_rearDisplayDeviceStates))
- .thenReturn(mRearDisplayStates);
+ .thenReturn(mapDeviceStateListToIdentifierArray(mRearDisplayStates));
when(mMockContext.getResources()
.getInteger(R.integer.config_deviceStateConcurrentRearDisplay))
- .thenReturn(mConcurrentDisplayState);
+ .thenReturn(mConcurrentDisplayState.getIdentifier());
+
+ mDeviceStateList.addAll(mOpenDeviceStates);
+ mDeviceStateList.addAll(mRearDisplayStates);
+ mDeviceStateList.add(mConcurrentDisplayState);
} else {
// Match the default value in framework resources
when(mMockContext.getResources()
@@ -196,12 +278,14 @@ public class DeviceStateControllerTests {
if (enableFold) {
when(mMockContext.getResources()
.getIntArray(R.array.config_foldedDeviceStates))
- .thenReturn(mFoldedStates);
+ .thenReturn(mapDeviceStateListToIdentifierArray(mFoldedStates));
+ mDeviceStateList.addAll(mFoldedStates);
}
if (enableHalfFold) {
when(mMockContext.getResources()
.getIntArray(R.array.config_halfFoldedDeviceStates))
- .thenReturn(mHalfFoldedStates);
+ .thenReturn(mapDeviceStateListToIdentifierArray(mHalfFoldedStates));
+ mDeviceStateList.addAll(mHalfFoldedStates);
}
}
@@ -210,11 +294,20 @@ public class DeviceStateControllerTests {
mMockDeviceStateManager = mock(DeviceStateManager.class);
when(mMockContext.getSystemService(DeviceStateManager.class))
.thenReturn(mMockDeviceStateManager);
+ when(mMockDeviceStateManager.getSupportedDeviceStates()).thenReturn(mDeviceStateList);
Resources mockRes = mock(Resources.class);
when(mMockContext.getResources()).thenReturn((mockRes));
mockFold(mSupportFold, mSupportHalfFold);
mTarget = new DeviceStateController(mMockContext, new WindowManagerGlobalLock());
mTarget.registerDeviceStateCallback(mDelegate, mExecutor);
}
+
+ private int[] mapDeviceStateListToIdentifierArray(List<DeviceState> deviceStates) {
+ int[] identifiers = new int[deviceStates.size()];
+ for (int i = 0; i < deviceStates.size(); i++) {
+ identifiers[i] = deviceStates.get(i).getIdentifier();
+ }
+ return identifiers;
+ }
}
}
diff --git a/tests/Input/assets/testPointerStrokeStyle.png b/tests/Input/assets/testPointerStrokeStyle.png
new file mode 100644
index 000000000000..4ddde70b2f0a
--- /dev/null
+++ b/tests/Input/assets/testPointerStrokeStyle.png
Binary files differ
diff --git a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
index d196b85a7466..e0f8c6d6ff4a 100644
--- a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
+++ b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
@@ -88,6 +88,35 @@ class PointerIconLoadingTest {
theme.applyStyle(
PointerIcon.vectorFillStyleToResource(PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_GREEN),
/* force= */ true)
+ theme.applyStyle(PointerIcon.vectorStrokeStyleToResource(
+ PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_WHITE), /* force= */ true)
+
+ val pointerIcon =
+ PointerIcon.getLoadedSystemIcon(
+ ContextThemeWrapper(context, theme),
+ PointerIcon.TYPE_ARROW,
+ /* useLargeIcons= */ false,
+ /* pointerScale= */ 1f)
+
+ pointerIcon.getBitmap().assertAgainstGolden(
+ screenshotRule,
+ testName.methodName,
+ exactScreenshotMatcher
+ )
+ }
+
+ @Test
+ fun testPointerStrokeStyle() {
+ assumeTrue(enableVectorCursors())
+ assumeTrue(enableVectorCursorA11ySettings())
+
+ val theme: Resources.Theme = context.getResources().newTheme()
+ theme.setTo(context.getTheme())
+ theme.applyStyle(
+ PointerIcon.vectorFillStyleToResource(PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK),
+ /* force= */ true)
+ theme.applyStyle(PointerIcon.vectorStrokeStyleToResource(
+ PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_BLACK), /* force= */ true)
val pointerIcon =
PointerIcon.getLoadedSystemIcon(
diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
index 489ef4444e1d..3722fefb12ad 100644
--- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
@@ -47,6 +47,8 @@ import android.net.ConnectivityModuleConnector.ConnectivityModuleHealthListener;
import android.os.Handler;
import android.os.SystemProperties;
import android.os.test.TestLooper;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
import android.util.AtomicFile;
@@ -288,7 +290,8 @@ public class CrashRecoveryTest {
}
@Test
- public void testBootLoopWithRescuePartyAndRollbackPackageHealthObserver() throws Exception {
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ public void testBootLoopWithRescuePartyAndRollbackObserver() throws Exception {
PackageWatchdog watchdog = createWatchdog();
RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
RollbackPackageHealthObserver rollbackObserver =
@@ -360,6 +363,56 @@ public class CrashRecoveryTest {
verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
}
+ @Test
+ @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ public void testBootLoopWithRescuePartyAndRollbackObserverNoFlags() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
+ RollbackPackageHealthObserver rollbackObserver =
+ setUpRollbackPackageHealthObserver(watchdog);
+
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(1);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(1);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+
+ watchdog.noteBoot();
+
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+ verify(rollbackObserver).executeBootLoopMitigation(1);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+ // Update the list of available rollbacks after executing bootloop mitigation once
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_HIGH,
+ ROLLBACK_INFO_MANUAL));
+
+ watchdog.noteBoot();
+
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+ verify(rollbackObserver).executeBootLoopMitigation(2);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+ // Update the list of available rollbacks after executing bootloop mitigation
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_MANUAL));
+
+ watchdog.noteBoot();
+
+ verify(rescuePartyObserver).executeBootLoopMitigation(2);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(3);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+ Mockito.reset(rescuePartyObserver);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(1);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+ }
+
RollbackPackageHealthObserver setUpRollbackPackageHealthObserver(PackageWatchdog watchdog) {
RollbackPackageHealthObserver rollbackObserver =
spy(new RollbackPackageHealthObserver(mSpyContext, mApexManager));