summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java7
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java8
-rw-r--r--core/api/test-current.txt11
-rw-r--r--core/java/android/app/ActivityManager.java1
-rw-r--r--core/java/android/app/IUidObserver.aidl3
-rw-r--r--core/java/android/app/PendingIntent.java29
-rw-r--r--core/java/android/app/UidObserver.java2
-rw-r--r--core/java/android/app/WallpaperColors.java10
-rw-r--r--core/java/android/app/WallpaperManager.java6
-rw-r--r--core/java/android/content/pm/PackageInstaller.java34
-rw-r--r--core/java/android/content/pm/ShortcutInfo.java21
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java29
-rw-r--r--core/java/android/hardware/soundtrigger/ConversionUtil.java46
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTriggerModule.java8
-rw-r--r--core/java/android/net/metrics/WakeupStats.java26
-rw-r--r--core/java/android/os/UserManager.java33
-rw-r--r--core/java/android/provider/Settings.java7
-rw-r--r--core/java/android/service/autofill/FillRequest.java2
-rw-r--r--core/java/android/view/InsetsFrameProvider.java59
-rw-r--r--core/java/android/view/InsetsSource.java22
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/android/view/autofill/AutofillManager.java104
-rw-r--r--core/java/android/view/autofill/AutofillRequestCallback.java76
-rw-r--r--core/java/android/view/autofill/IAutoFillManagerClient.aidl8
-rw-r--r--core/java/android/view/inputmethod/InlineSuggestionsRequest.java131
-rw-r--r--core/java/android/window/ScreenCapture.java35
-rw-r--r--core/java/android/window/StartingWindowRemovalInfo.java29
-rw-r--r--core/java/android/window/TransitionInfo.java6
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java4
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java2
-rw-r--r--core/jni/android_window_ScreenCapture.cpp29
-rw-r--r--core/proto/android/companion/telecom.proto29
-rw-r--r--core/res/res/drawable-hdpi/pointer_all_scroll.pngbin1052 -> 1137 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_horizontal_double_arrow.pngbin826 -> 886 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_top_left_diagonal_double_arrow.pngbin864 -> 960 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_top_right_diagonal_double_arrow.pngbin863 -> 976 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_vertical_double_arrow.pngbin848 -> 919 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_all_scroll.pngbin575 -> 632 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_all_scroll_large.pngbin2104 -> 2251 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.pngbin450 -> 504 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_horizontal_double_arrow_large.pngbin1687 -> 1785 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.pngbin490 -> 538 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow_large.pngbin1783 -> 1903 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.pngbin499 -> 543 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow_large.pngbin1767 -> 1920 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_vertical_double_arrow.pngbin464 -> 517 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_vertical_double_arrow_large.pngbin1730 -> 1871 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_all_scroll.pngbin1518 -> 1666 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_all_scroll_large.pngbin5642 -> 6181 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.pngbin1192 -> 1332 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.pngbin4436 -> 4922 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.pngbin1265 -> 1422 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.pngbin4780 -> 5315 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.pngbin1263 -> 1408 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.pngbin4712 -> 5340 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.pngbin1238 -> 1369 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.pngbin4710 -> 5108 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/pointer_all_scroll.pngbin2636 -> 2916 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/pointer_horizontal_double_arrow.pngbin2076 -> 2328 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/pointer_top_left_diagonal_double_arrow.pngbin2212 -> 2513 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/pointer_top_right_diagonal_double_arrow.pngbin2183 -> 2525 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/pointer_vertical_double_arrow.pngbin2179 -> 2428 bytes
-rw-r--r--core/res/res/layout-television/user_switching_dialog.xml29
-rw-r--r--core/res/res/values/config.xml21
-rw-r--r--core/res/res/values/dimens.xml8
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp15
-rw-r--r--core/tests/coretests/src/android/view/InsetsSourceTest.java20
-rw-r--r--data/etc/com.android.systemui.xml1
-rw-r--r--data/etc/privapp-permissions-platform.xml4
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java36
-rw-r--r--graphics/java/android/graphics/MeshSpecification.java75
-rw-r--r--libs/WindowManager/Shell/Android.bp29
-rw-r--r--libs/WindowManager/Shell/res/color/taskbar_background.xml20
-rw-r--r--libs/WindowManager/Shell/res/color/taskbar_background_dark.xml (renamed from libs/WindowManager/Shell/res/color-night/taskbar_background.xml)0
-rw-r--r--libs/WindowManager/Shell/res/values-night/colors.xml1
-rw-r--r--libs/WindowManager/Shell/res/values/colors.xml4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java46
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt108
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java125
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/IDragAndDrop.aidl28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java103
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java51
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSplashWindowCreator.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java130
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java60
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidTest.xml3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt47
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt139
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt136
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt54
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt19
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt28
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt44
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt21
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt24
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt41
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt39
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt42
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt41
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt30
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt38
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt99
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt28
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt79
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt83
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt70
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt76
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt94
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt91
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt94
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt93
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt79
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt155
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt81
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt79
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt79
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt76
-rw-r--r--libs/WindowManager/Shell/tests/unittest/Android.bp2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt52
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java18
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java19
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java212
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt232
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt300
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt12
-rw-r--r--libs/hwui/Tonemapper.cpp1
-rw-r--r--libs/hwui/effects/GainmapRenderer.cpp2
-rw-r--r--libs/hwui/effects/GainmapRenderer.h2
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp2
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.cpp2
-rw-r--r--libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp2
-rw-r--r--libs/hwui/private/hwui/DrawGlInfo.h5
-rw-r--r--libs/hwui/private/hwui/DrawVkInfo.h5
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp9
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp29
-rw-r--r--libs/hwui/renderthread/VulkanManager.h3
-rw-r--r--libs/hwui/utils/Color.cpp8
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl8
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEventSys.aidl36
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/RecognitionEventSys.aidl36
-rw-r--r--media/java/android/media/AudioSystem.java63
-rw-r--r--media/java/android/media/soundtrigger/SoundTriggerInstrumentation.java33
-rw-r--r--native/android/activity_manager.cpp4
-rw-r--r--packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java16
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java5
-rw-r--r--packages/CredentialManager/AndroidManifest.xml9
-rw-r--r--packages/CredentialManager/res/values/strings.xml14
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt4
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialProviderReceiver.kt35
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt18
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt60
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt108
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/UserConfigRepo.kt14
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt193
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt18
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java13
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java107
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java244
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java81
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java14
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java17
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java50
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java3
-rw-r--r--packages/Shell/AndroidManifest.xml133
-rw-r--r--packages/SystemUI/Android.bp1
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/animation/Android.bp1
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java212
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java219
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt39
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt14
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt1
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt2
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt6
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt12
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt2
-rw-r--r--packages/SystemUI/log/.gitignore9
-rw-r--r--packages/SystemUI/log/Android.bp38
-rw-r--r--packages/SystemUI/log/AndroidManifest.xml22
-rw-r--r--packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLogger.kt (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLogger.kt)2
-rw-r--r--packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLoggerImpl.kt (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLoggerImpl.kt)2
-rw-r--r--packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt)2
-rw-r--r--packages/SystemUI/log/src/com/android/systemui/log/LogLevel.kt (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogLevel.kt)2
-rw-r--r--packages/SystemUI/log/src/com/android/systemui/log/LogMessage.kt (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessage.kt)2
-rw-r--r--packages/SystemUI/log/src/com/android/systemui/log/LogMessageImpl.kt (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessageImpl.kt)2
-rw-r--r--packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTracker.kt (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTracker.kt)2
-rw-r--r--packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt)2
-rw-r--r--packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerProd.kt (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerProd.kt)2
-rw-r--r--packages/SystemUI/plugin/Android.bp4
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt2
-rw-r--r--packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml21
-rw-r--r--packages/SystemUI/res/drawable/ic_keyboard_backlight.xml12
-rw-r--r--packages/SystemUI/res/layout/combined_qs_header.xml18
-rw-r--r--packages/SystemUI/res/layout/smart_action_button.xml4
-rw-r--r--packages/SystemUI/res/layout/smart_reply_button.xml4
-rw-r--r--packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml12
-rw-r--r--packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml3
-rw-r--r--packages/SystemUI/res/values-sw720dp/dimens.xml2
-rw-r--r--packages/SystemUI/res/values/colors.xml5
-rw-r--r--packages/SystemUI/res/values/dimens.xml52
-rw-r--r--packages/SystemUI/res/values/ids.xml3
-rw-r--r--packages/SystemUI/res/values/strings.xml4
-rw-r--r--packages/SystemUI/res/xml/qqs_header.xml8
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt172
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java58
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt32
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt36
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/ClockEventController.kt4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardBouncerMessages.kt323
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java24
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java21
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java36
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java16
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java18
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt59
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt60
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java122
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/data/repository/CommonRepositoryModule.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt118
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelperWrapper.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt125
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/BiometricLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/ShadeWindowLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogBuffer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogBuffer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java118
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto3
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/wrapper/DisplayUtilsWrapper.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt55
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt83
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java68
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt196
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt176
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt137
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt (renamed from packages/SystemUI/plugin/tests/log/LogBufferTest.kt)1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt150
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt111
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt109
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt450
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java174
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/condition/FakeCondition.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt82
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java96
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt108
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt2
-rw-r--r--services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java293
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java218
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java20
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java49
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java16
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java27
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java35
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java4
-rw-r--r--services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java54
-rw-r--r--services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java21
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java41
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java9
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueImpl.java4
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java27
-rw-r--r--services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java31
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java5
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java1
-rw-r--r--services/core/java/com/android/server/am/UidObserverController.java7
-rw-r--r--services/core/java/com/android/server/am/UidRecord.java20
-rw-r--r--services/core/java/com/android/server/am/UserController.java327
-rw-r--r--services/core/java/com/android/server/am/UserSwitchingDialog.java98
-rw-r--r--services/core/java/com/android/server/app/GameManagerService.java12
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java86
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java811
-rw-r--r--services/core/java/com/android/server/audio/AudioSystemAdapter.java15
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java93
-rw-r--r--services/core/java/com/android/server/audio/SoundDoseHelper.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/SensorList.java97
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java112
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java169
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java17
-rw-r--r--services/core/java/com/android/server/connectivity/NetdEventListenerService.java23
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java55
-rw-r--r--services/core/java/com/android/server/display/color/CctEvaluator.java108
-rw-r--r--services/core/java/com/android/server/display/color/ColorDisplayService.java85
-rw-r--r--services/core/java/com/android/server/display/color/ColorTemperatureTintController.java38
-rw-r--r--services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java162
-rw-r--r--services/core/java/com/android/server/display/color/TintController.java7
-rw-r--r--services/core/java/com/android/server/input/KeyboardLayoutManager.java2
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java18
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java11
-rw-r--r--services/core/java/com/android/server/notification/PermissionHelper.java14
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java18
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java22
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java213
-rw-r--r--services/core/java/com/android/server/pm/UserJourneyLogger.java552
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java222
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java10
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java9
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java47
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java108
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java27
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java20
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java29
-rw-r--r--services/core/java/com/android/server/wm/AsyncRotationController.java31
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java9
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java8
-rw-r--r--services/core/java/com/android/server/wm/FadeAnimationController.java12
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java40
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java7
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java2
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java18
-rw-r--r--services/core/java/com/android/server/wm/Transition.java49
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java55
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java128
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java19
-rw-r--r--services/core/jni/com_android_server_am_CachedAppOptimizer.cpp12
-rw-r--r--services/credentials/java/com/android/server/credentials/ClearRequestSession.java8
-rw-r--r--services/credentials/java/com/android/server/credentials/CreateRequestSession.java8
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java22
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java12
-rw-r--r--services/credentials/java/com/android/server/credentials/GetRequestSession.java8
-rw-r--r--services/credentials/java/com/android/server/credentials/MetricUtilities.java61
-rw-r--r--services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java2
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderClearSession.java2
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderCreateSession.java32
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderGetSession.java37
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java13
-rw-r--r--services/credentials/java/com/android/server/credentials/RemoteCredentialService.java4
-rw-r--r--services/credentials/java/com/android/server/credentials/RequestSession.java4
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/ApiName.java4
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java2
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java114
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java118
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/EntryEnum.java4
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java14
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java114
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java49
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/shared/ResponseCollective.java115
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java32
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java141
-rw-r--r--services/java/com/android/server/SystemServer.java4
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java23
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java76
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorListTest.java66
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java30
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java36
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java46
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java91
-rw-r--r--services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt34
-rw-r--r--services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java30
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserJourneyLoggerTest.java580
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java17
-rw-r--r--services/tests/servicestests/utils/com/android/server/testutils/OWNERS1
-rw-r--r--services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java (renamed from services/tests/wmtests/src/com/android/server/wm/StubTransaction.java)4
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java33
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/DeviceStateHandlerTest.java261
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java57
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java76
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java99
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java192
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java193
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DimmerTests.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java9
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java16
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/DeviceStateHandler.java279
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java158
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java211
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java59
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java28
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java17
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java12
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java23
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java15
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java13
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java30
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java13
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java19
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java17
-rw-r--r--services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java4
-rw-r--r--telephony/java/android/telephony/DisconnectCause.java327
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteManager.java25
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl19
-rw-r--r--tests/FlickerTests/AndroidTest.xml3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt50
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java183
-rw-r--r--tests/SilkFX/res/layout/gainmap_image.xml33
-rw-r--r--tests/SilkFX/res/layout/gainmap_metadata.xml264
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt20
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt284
747 files changed, 15390 insertions, 7160 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 577260e5106f..8a4b4647f94b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1560,7 +1560,8 @@ public class JobSchedulerService extends com.android.server.SystemService
jobStatus.getJob().getMinLatencyMillis(),
jobStatus.getEstimatedNetworkDownloadBytes(),
jobStatus.getEstimatedNetworkUploadBytes(),
- jobStatus.getWorkCount());
+ jobStatus.getWorkCount(),
+ ActivityManager.processStateAmToProto(mUidProcStates.get(jobStatus.getUid())));
// If the job is immediately ready to run, then we can just immediately
// put it in the pending list and try to schedule it. This is especially
@@ -1935,6 +1936,7 @@ public class JobSchedulerService extends com.android.server.SystemService
* {@code incomingJob} is non-null, it replaces {@code cancelled} in the store of
* currently scheduled jobs.
*/
+ @GuardedBy("mLock")
private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob,
@JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
@@ -1986,7 +1988,8 @@ public class JobSchedulerService extends com.android.server.SystemService
cancelled.getJob().getMinLatencyMillis(),
cancelled.getEstimatedNetworkDownloadBytes(),
cancelled.getEstimatedNetworkUploadBytes(),
- cancelled.getWorkCount());
+ cancelled.getWorkCount(),
+ ActivityManager.processStateAmToProto(mUidProcStates.get(cancelled.getUid())));
}
// If this is a replacement, bring in the new version of the job
if (incomingJob != null) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index fb36cdec490f..f95df4471c29 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -25,6 +25,7 @@ import android.Manifest;
import android.annotation.BytesLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.Notification;
import android.app.compat.CompatChanges;
@@ -476,7 +477,8 @@ public final class JobServiceContext implements ServiceConnection {
job.getJob().getMinLatencyMillis(),
job.getEstimatedNetworkDownloadBytes(),
job.getEstimatedNetworkUploadBytes(),
- job.getWorkCount());
+ job.getWorkCount(),
+ ActivityManager.processStateAmToProto(mService.getUidProcState(job.getUid())));
final String sourcePackage = job.getSourcePackageName();
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
final String componentPackage = job.getServiceComponent().getPackageName();
@@ -1447,7 +1449,9 @@ public final class JobServiceContext implements ServiceConnection {
completedJob.getJob().getMinLatencyMillis(),
completedJob.getEstimatedNetworkDownloadBytes(),
completedJob.getEstimatedNetworkUploadBytes(),
- completedJob.getWorkCount());
+ completedJob.getWorkCount(),
+ ActivityManager
+ .processStateAmToProto(mService.getUidProcState(completedJob.getUid())));
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER, "JobScheduler",
getId());
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 332c53cb224f..d97f71847592 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3632,18 +3632,12 @@ package android.view.autofill {
}
public final class AutofillManager {
- method public void clearAutofillRequestCallback();
- method @RequiresPermission(android.Manifest.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS) public void setAutofillRequestCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.autofill.AutofillRequestCallback);
field public static final String ANY_HINT = "any";
field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0
field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0
}
- public interface AutofillRequestCallback {
- method public void onFillRequest(@Nullable android.view.inputmethod.InlineSuggestionsRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
- }
-
}
package android.view.contentcapture {
@@ -3767,11 +3761,6 @@ package android.view.inputmethod {
method @NonNull public static android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(@NonNull android.widget.inline.InlinePresentationSpec, @NonNull String, @Nullable String[], @NonNull String, boolean);
}
- public static final class InlineSuggestionsRequest.Builder {
- method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setClientSupported(boolean);
- method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setServiceSupported(boolean);
- }
-
public final class InlineSuggestionsResponse implements android.os.Parcelable {
method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>);
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 521bf05d9d4f..e2ef00525902 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -771,6 +771,7 @@ public class ActivityManager {
/**
* The set of flags for process capability.
+ * Keep it in sync with ProcessCapability in atoms.proto.
* @hide
*/
@IntDef(flag = true, prefix = { "PROCESS_CAPABILITY_" }, value = {
diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl
index 0c920f1359f3..60c2eeddac63 100644
--- a/core/java/android/app/IUidObserver.aidl
+++ b/core/java/android/app/IUidObserver.aidl
@@ -58,8 +58,9 @@ oneway interface IUidObserver {
* Report a proc oom adj change associated with a uid.
*
* @param uid The uid for which the state change is being reported.
+ * @param adj The minimum OOM adj among all processes with this uid.
*/
- void onUidProcAdjChanged(int uid);
+ void onUidProcAdjChanged(int uid, int adj);
// =============== End of transactions used on native side as well ============================
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 99a7fa21b911..705b5ee84d01 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -407,7 +407,7 @@ public final class PendingIntent implements Parcelable {
}
private static void checkPendingIntent(int flags, @NonNull Intent intent,
- @NonNull Context context) {
+ @NonNull Context context, boolean isActivityResultType) {
final boolean isFlagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0;
final boolean isFlagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0;
final String packageName = context.getPackageName();
@@ -428,11 +428,12 @@ public final class PendingIntent implements Parcelable {
throw new IllegalArgumentException(msg);
}
- // For apps with target SDK < U, warn that creation or retrieval of a mutable
- // implicit PendingIntent will be blocked from target SDK U onwards for security
- // reasons. The block itself happens on the server side, but this warning has to
- // stay here to preserve the client side stack trace for app developers.
- if (isNewMutableDisallowedImplicitPendingIntent(flags, intent)
+ // For apps with target SDK < U, warn that creation or retrieval of a mutable implicit
+ // PendingIntent that is not of type {@link ActivityManager#INTENT_SENDER_ACTIVITY_RESULT}
+ // will be blocked from target SDK U onwards for security reasons. The block itself
+ // happens on the server side, but this warning has to stay here to preserve the client
+ // side stack trace for app developers.
+ if (isNewMutableDisallowedImplicitPendingIntent(flags, intent, isActivityResultType)
&& !Compatibility.isChangeEnabled(BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT)) {
String msg = "New mutable implicit PendingIntent: pkg=" + packageName
+ ", action=" + intent.getAction()
@@ -445,7 +446,13 @@ public final class PendingIntent implements Parcelable {
/** @hide */
public static boolean isNewMutableDisallowedImplicitPendingIntent(int flags,
- @NonNull Intent intent) {
+ @NonNull Intent intent, boolean isActivityResultType) {
+ if (isActivityResultType) {
+ // Pending intents of type {@link ActivityManager#INTENT_SENDER_ACTIVITY_RESULT}
+ // should be ignored as they are intrinsically tied to a target which means they
+ // are already explicit.
+ return false;
+ }
boolean isFlagNoCreateSet = (flags & PendingIntent.FLAG_NO_CREATE) != 0;
boolean isFlagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0;
boolean isImplicit = (intent.getComponent() == null) && (intent.getPackage() == null);
@@ -534,7 +541,7 @@ public final class PendingIntent implements Parcelable {
@NonNull Intent intent, int flags, Bundle options, UserHandle user) {
String packageName = context.getPackageName();
String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
- checkPendingIntent(flags, intent, context);
+ checkPendingIntent(flags, intent, context, /* isActivityResultType */ false);
try {
intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
@@ -668,7 +675,7 @@ public final class PendingIntent implements Parcelable {
intents[i].migrateExtraStreamToClipData(context);
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
- checkPendingIntent(flags, intents[i], context);
+ checkPendingIntent(flags, intents[i], context, /* isActivityResultType */ false);
}
try {
IIntentSender target =
@@ -721,7 +728,7 @@ public final class PendingIntent implements Parcelable {
Intent intent, int flags, UserHandle userHandle) {
String packageName = context.getPackageName();
String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
- checkPendingIntent(flags, intent, context);
+ checkPendingIntent(flags, intent, context, /* isActivityResultType */ false);
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
@@ -800,7 +807,7 @@ public final class PendingIntent implements Parcelable {
Intent intent, int flags, int serviceKind) {
String packageName = context.getPackageName();
String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
- checkPendingIntent(flags, intent, context);
+ checkPendingIntent(flags, intent, context, /* isActivityResultType */ false);
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
diff --git a/core/java/android/app/UidObserver.java b/core/java/android/app/UidObserver.java
index 9e928073ac5c..519662448e91 100644
--- a/core/java/android/app/UidObserver.java
+++ b/core/java/android/app/UidObserver.java
@@ -41,7 +41,7 @@ public class UidObserver extends IUidObserver.Stub {
}
@Override
- public void onUidProcAdjChanged(int uid) {
+ public void onUidProcAdjChanged(int uid, int adj) {
}
@Override
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index a34a50c4b7b0..be1d8b8ad7d3 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -213,9 +213,17 @@ public final class WallpaperColors implements Parcelable {
.resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
.generate();
} else {
+ // in any case, always use between 5 and 128 clusters
+ int minClusters = 5;
+ int maxClusters = 128;
+
+ // if the bitmap is very small, use bitmapArea/16 clusters instead of 128
+ int minPixelsPerCluster = 16;
+ int numberOfColors = Math.max(minClusters,
+ Math.min(maxClusters, bitmapArea / minPixelsPerCluster));
palette = Palette
.from(bitmap, new CelebiQuantizer())
- .maximumColorCount(128)
+ .maximumColorCount(numberOfColors)
.resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
.generate();
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6592019dc0d9..f6733047d965 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -822,6 +822,10 @@ public class WallpaperManager {
*/
@TestApi
public boolean isLockscreenLiveWallpaperEnabled() {
+ return isLockscreenLiveWallpaperEnabledHelper();
+ }
+
+ private static boolean isLockscreenLiveWallpaperEnabledHelper() {
if (sGlobals == null) {
sIsLockscreenLiveWallpaperEnabled = SystemProperties.getBoolean(
"persist.wm.debug.lockscreen_live_wallpaper", false);
@@ -2757,7 +2761,7 @@ public class WallpaperManager {
public static InputStream openDefaultWallpaper(Context context, @SetWallpaperFlags int which) {
final String whichProp;
final int defaultResId;
- if (which == FLAG_LOCK && !sIsLockscreenLiveWallpaperEnabled) {
+ if (which == FLAG_LOCK && !isLockscreenLiveWallpaperEnabledHelper()) {
/* Factory-default lock wallpapers are not yet supported
whichProp = PROP_LOCK_WALLPAPER;
defaultResId = com.android.internal.R.drawable.default_lock_wallpaper;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index de66f050c007..56f6f8206d30 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2072,6 +2072,25 @@ public class PackageInstaller {
return new InstallInfo(result);
}
+ /**
+ * Parse a single APK file passed as an FD to get install relevant information about
+ * the package wrapped in {@link InstallInfo}.
+ * @throws PackageParsingException if the package source file(s) provided is(are) not valid,
+ * or the parser isn't able to parse the supplied source(s).
+ * @hide
+ */
+ @NonNull
+ public InstallInfo readInstallInfo(@NonNull ParcelFileDescriptor pfd,
+ @Nullable String debugPathName, int flags) throws PackageParsingException {
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<PackageLite> result = ApkLiteParseUtils.parseMonolithicPackageLite(input,
+ pfd.getFileDescriptor(), debugPathName, flags);
+ if (result.isError()) {
+ throw new PackageParsingException(result.getErrorCode(), result.getErrorMessage());
+ }
+ return new InstallInfo(result);
+ }
+
// (b/239722738) This class serves as a bridge between the PackageLite class, which
// is a hidden class, and the consumers of this class. (e.g. InstallInstalling.java)
// This is a part of an effort to remove dependency on hidden APIs and use SystemAPIs or
@@ -2125,6 +2144,21 @@ public class PackageInstaller {
public long calculateInstalledSize(@NonNull SessionParams params) throws IOException {
return InstallLocationUtils.calculateInstalledSize(mPkg, params.abiOverride);
}
+
+ /**
+ * @param params {@link SessionParams} of the installation
+ * @param pfd of an APK opened for read
+ * @return Total disk space occupied by an application after installation.
+ * Includes the size of the raw APKs, possibly unpacked resources, raw dex metadata files,
+ * and all relevant native code.
+ * @throws IOException when size of native binaries cannot be calculated.
+ * @hide
+ */
+ public long calculateInstalledSize(@NonNull SessionParams params,
+ @NonNull ParcelFileDescriptor pfd) throws IOException {
+ return InstallLocationUtils.calculateInstalledSize(mPkg, params.abiOverride,
+ pfd.getFileDescriptor());
+ }
}
/**
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 295df5cc42d0..be40143f5bd3 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -50,7 +50,6 @@ import android.view.contentcapture.ContentCaptureContext;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
-import java.lang.IllegalArgumentException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -285,6 +284,12 @@ public final class ShortcutInfo implements Parcelable {
*/
public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
+ /**
+ * The maximum length of Shortcut ID. IDs will be truncated at this limit.
+ * @hide
+ */
+ public static final int MAX_ID_LENGTH = 1000;
+
/** @hide */
@IntDef(prefix = { "DISABLED_REASON_" }, value = {
DISABLED_REASON_NOT_DISABLED,
@@ -477,8 +482,7 @@ public final class ShortcutInfo implements Parcelable {
private ShortcutInfo(Builder b) {
mUserId = b.mContext.getUserId();
-
- mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
+ mId = getSafeId(Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided"));
// Note we can't do other null checks here because SM.updateShortcuts() takes partial
// information.
@@ -584,6 +588,14 @@ public final class ShortcutInfo implements Parcelable {
return ret;
}
+ @NonNull
+ private static String getSafeId(@NonNull String id) {
+ if (id.length() > MAX_ID_LENGTH) {
+ return id.substring(0, MAX_ID_LENGTH);
+ }
+ return id;
+ }
+
/**
* Throws if any of the mandatory fields is not set.
*
@@ -2342,7 +2354,8 @@ public final class ShortcutInfo implements Parcelable {
final ClassLoader cl = getClass().getClassLoader();
mUserId = source.readInt();
- mId = source.readString8();
+ mId = getSafeId(Preconditions.checkStringNotEmpty(source.readString8(),
+ "Shortcut ID must be provided"));
mPackageName = source.readString8();
mActivity = source.readParcelable(cl, android.content.ComponentName.class);
mFlags = source.readInt();
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index a4339d41dfd2..d209b35ac810 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -109,7 +109,7 @@ public class ApkLiteParseUtils {
}
/**
- * Parse lightweight details about a single APK files.
+ * Parse lightweight details about a single APK file.
*/
public static ParseResult<PackageLite> parseMonolithicPackageLite(ParseInput input,
File packageFile, int flags) {
@@ -135,6 +135,33 @@ public class ApkLiteParseUtils {
}
/**
+ * Parse lightweight details about a single APK file passed as an FD.
+ */
+ public static ParseResult<PackageLite> parseMonolithicPackageLite(ParseInput input,
+ FileDescriptor packageFd, String debugPathName, int flags) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
+ try {
+ final ParseResult<ApkLite> result = parseApkLite(input, packageFd, debugPathName,
+ flags);
+ if (result.isError()) {
+ return input.error(result);
+ }
+
+ final ApkLite baseApk = result.getResult();
+ final String packagePath = debugPathName;
+ return input.success(
+ new PackageLite(packagePath, baseApk.getPath(), baseApk, null /* splitNames */,
+ null /* isFeatureSplits */, null /* usesSplitNames */,
+ null /* configForSplit */, null /* splitApkPaths */,
+ null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(),
+ null /* requiredSplitTypes */, null, /* splitTypes */
+ baseApk.isAllowUpdateOwnership()));
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ /**
* Parse lightweight details about a directory of APKs.
*
* @param packageDir is the folder that contains split apks for a regular app
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index 888047d95f80..21fe686fa2e3 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -32,10 +32,12 @@ import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionMode;
import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.ParcelFileDescriptor;
-import android.system.ErrnoException;
import android.os.SharedMemory;
+import android.system.ErrnoException;
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -219,36 +221,40 @@ public class ConversionUtil {
return new SoundTrigger.ConfidenceLevel(apiLevel.userId, apiLevel.levelPercent);
}
- public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(
- int modelHandle, int captureSession, RecognitionEvent aidlEvent) {
+ public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(int modelHandle,
+ int captureSession, RecognitionEventSys aidlEvent) {
+ RecognitionEvent recognitionEvent = aidlEvent.recognitionEvent;
// The API recognition event doesn't allow for a null audio format, even though it doesn't
// always make sense. We thus replace it with a default.
- AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.audioConfig,
+ AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(recognitionEvent.audioConfig,
true /*isInput*/);
- // TODO(b/265852186) propagate a timestamp from aidl interfaces
- return new SoundTrigger.GenericRecognitionEvent(aidlEvent.status, modelHandle,
- aidlEvent.captureAvailable, captureSession, aidlEvent.captureDelayMs,
- aidlEvent.capturePreambleMs, aidlEvent.triggerInData, audioFormat, aidlEvent.data,
- aidlEvent.recognitionStillActive, -1 /* halEventReceivedMillis */);
+ return new SoundTrigger.GenericRecognitionEvent(recognitionEvent.status, modelHandle,
+ recognitionEvent.captureAvailable, captureSession, recognitionEvent.captureDelayMs,
+ recognitionEvent.capturePreambleMs, recognitionEvent.triggerInData, audioFormat,
+ recognitionEvent.data,
+ recognitionEvent.recognitionStillActive, aidlEvent.halEventReceivedMillis);
}
public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent(
- int modelHandle, int captureSession,
- PhraseRecognitionEvent aidlEvent) {
+ int modelHandle, int captureSession, PhraseRecognitionEventSys aidlEvent) {
+ PhraseRecognitionEvent recognitionEvent = aidlEvent.phraseRecognitionEvent;
SoundTrigger.KeyphraseRecognitionExtra[] apiExtras =
- new SoundTrigger.KeyphraseRecognitionExtra[aidlEvent.phraseExtras.length];
- for (int i = 0; i < aidlEvent.phraseExtras.length; ++i) {
- apiExtras[i] = aidl2apiPhraseRecognitionExtra(aidlEvent.phraseExtras[i]);
+ new SoundTrigger.KeyphraseRecognitionExtra[recognitionEvent.phraseExtras.length];
+ for (int i = 0; i < recognitionEvent.phraseExtras.length; ++i) {
+ apiExtras[i] = aidl2apiPhraseRecognitionExtra(recognitionEvent.phraseExtras[i]);
}
// The API recognition event doesn't allow for a null audio format, even though it doesn't
// always make sense. We thus replace it with a default.
- AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.common.audioConfig,
+ AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(
+ recognitionEvent.common.audioConfig,
true /*isInput*/);
- // TODO(b/265852186) propagate a timestamp from aidl interfaces
- return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
- aidlEvent.common.captureAvailable, captureSession, aidlEvent.common.captureDelayMs,
- aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData, audioFormat,
- aidlEvent.common.data, apiExtras, -1 /* halEventReceivedMillis */);
+ return new SoundTrigger.KeyphraseRecognitionEvent(recognitionEvent.common.status,
+ modelHandle,
+ recognitionEvent.common.captureAvailable, captureSession,
+ recognitionEvent.common.captureDelayMs,
+ recognitionEvent.common.capturePreambleMs, recognitionEvent.common.triggerInData,
+ audioFormat,
+ recognitionEvent.common.data, apiExtras, aidlEvent.halEventReceivedMillis);
}
// In case of a null input returns a non-null valid output.
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 37c5213e0359..5cdbe233aa3b 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -22,13 +22,13 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.media.permission.ClearCallingIdentityContext;
import android.media.permission.Identity;
import android.media.permission.SafeCloseable;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -398,7 +398,7 @@ public class SoundTriggerModule {
}
@Override
- public synchronized void onRecognition(int handle, RecognitionEvent event,
+ public synchronized void onRecognition(int handle, RecognitionEventSys event,
int captureSession)
throws RemoteException {
Message m = mHandler.obtainMessage(EVENT_RECOGNITION,
@@ -407,7 +407,7 @@ public class SoundTriggerModule {
}
@Override
- public synchronized void onPhraseRecognition(int handle, PhraseRecognitionEvent event,
+ public synchronized void onPhraseRecognition(int handle, PhraseRecognitionEventSys event,
int captureSession)
throws RemoteException {
Message m = mHandler.obtainMessage(EVENT_RECOGNITION,
diff --git a/core/java/android/net/metrics/WakeupStats.java b/core/java/android/net/metrics/WakeupStats.java
index bb36536fe2ce..fac747c8f1a3 100644
--- a/core/java/android/net/metrics/WakeupStats.java
+++ b/core/java/android/net/metrics/WakeupStats.java
@@ -80,18 +80,20 @@ public class WakeupStats {
break;
}
- switch (ev.dstHwAddr.getAddressType()) {
- case MacAddress.TYPE_UNICAST:
- l2UnicastCount++;
- break;
- case MacAddress.TYPE_MULTICAST:
- l2MulticastCount++;
- break;
- case MacAddress.TYPE_BROADCAST:
- l2BroadcastCount++;
- break;
- default:
- break;
+ if (ev.dstHwAddr != null) {
+ switch (ev.dstHwAddr.getAddressType()) {
+ case MacAddress.TYPE_UNICAST:
+ l2UnicastCount++;
+ break;
+ case MacAddress.TYPE_MULTICAST:
+ l2MulticastCount++;
+ break;
+ case MacAddress.TYPE_BROADCAST:
+ l2BroadcastCount++;
+ break;
+ default:
+ break;
+ }
}
increment(ethertypes, ev.ethertype);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 24e28e95cd98..5bcbaa10e95b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -65,7 +65,6 @@ import android.util.Log;
import android.view.WindowManager.LayoutParams;
import com.android.internal.R;
-import com.android.internal.util.FrameworkStatsLog;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -2533,38 +2532,6 @@ public class UserManager {
}
/**
- * Returns the enum defined in the statsd UserLifecycleJourneyReported atom corresponding to the
- * user type.
- * @hide
- */
- public static int getUserTypeForStatsd(@NonNull String userType) {
- switch (userType) {
- case USER_TYPE_FULL_SYSTEM:
- return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SYSTEM;
- case USER_TYPE_FULL_SECONDARY:
- return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY;
- case USER_TYPE_FULL_GUEST:
- return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_GUEST;
- case USER_TYPE_FULL_DEMO:
- return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_DEMO;
- case USER_TYPE_FULL_RESTRICTED:
- return FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_RESTRICTED;
- case USER_TYPE_PROFILE_MANAGED:
- return FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__PROFILE_MANAGED;
- case USER_TYPE_SYSTEM_HEADLESS:
- return FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__SYSTEM_HEADLESS;
- case USER_TYPE_PROFILE_CLONE:
- return FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__PROFILE_CLONE;
- default:
- return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN;
- }
- }
-
- /**
* @hide
* @deprecated Use {@link #isRestrictedProfile()}
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4a46beb670de..329a2fa57c08 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7175,6 +7175,13 @@ public final class Settings {
public static final String CREDENTIAL_SERVICE = "credential_service";
/**
+ * The currently selected primary credential service flattened ComponentName.
+ *
+ * @hide
+ */
+ public static final String CREDENTIAL_SERVICE_PRIMARY = "credential_service_primary";
+
+ /**
* The currently selected autofill service flattened ComponentName.
* @hide
*/
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 4a848dd86463..8afae74735e2 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -97,8 +97,6 @@ public final class FillRequest implements Parcelable {
*/
public static final @RequestFlags int FLAG_VIEW_NOT_FOCUSED = 0x10;
- // The flag value 0x20 has been defined in AutofillManager.
-
/**
* Indicates the request supports fill dialog presentation for the fields, the
* system will send the request when the activity just started.
diff --git a/core/java/android/view/InsetsFrameProvider.java b/core/java/android/view/InsetsFrameProvider.java
index a69af24756a0..470c2801d838 100644
--- a/core/java/android/view/InsetsFrameProvider.java
+++ b/core/java/android/view/InsetsFrameProvider.java
@@ -62,9 +62,7 @@ public class InsetsFrameProvider implements Parcelable {
*/
public static final int SOURCE_ARBITRARY_RECTANGLE = 3;
- private final IBinder mOwner;
- private final int mIndex;
- private final @InsetsType int mType;
+ private final int mId;
/**
* The selection of the starting rectangle to be converted into source frame.
@@ -122,30 +120,30 @@ public class InsetsFrameProvider implements Parcelable {
* @param type the {@link InsetsType}.
* @see InsetsSource#createId(Object, int, int)
*/
- public InsetsFrameProvider(IBinder owner, @IntRange(from = 0, to = 2047) int index,
+ public InsetsFrameProvider(Object owner, @IntRange(from = 0, to = 2047) int index,
@InsetsType int type) {
- if (index < 0 || index >= 2048) {
- throw new IllegalArgumentException();
- }
-
- // This throws IllegalArgumentException if the type is not valid.
- WindowInsets.Type.indexOf(type);
-
- mOwner = owner;
- mIndex = index;
- mType = type;
+ mId = InsetsSource.createId(owner, index, type);
}
- public IBinder getOwner() {
- return mOwner;
+ /**
+ * Returns an unique integer which identifies the insets source.
+ */
+ public int getId() {
+ return mId;
}
+ /**
+ * Returns the index specified in {@link #InsetsFrameProvider(IBinder, int, int)}.
+ */
public int getIndex() {
- return mIndex;
+ return InsetsSource.getIndex(mId);
}
+ /**
+ * Returns the {@link InsetsType} specified in {@link #InsetsFrameProvider(IBinder, int, int)}.
+ */
public int getType() {
- return mType;
+ return InsetsSource.getType(mId);
}
public InsetsFrameProvider setSource(int source) {
@@ -211,9 +209,9 @@ public class InsetsFrameProvider implements Parcelable {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("InsetsFrameProvider: {");
- sb.append("owner=").append(mOwner);
- sb.append(", index=").append(mIndex);
- sb.append(", type=").append(WindowInsets.Type.toString(mType));
+ sb.append("id=#").append(Integer.toHexString(mId));
+ sb.append(", index=").append(getIndex());
+ sb.append(", type=").append(WindowInsets.Type.toString(getType()));
sb.append(", source=").append(sourceToString(mSource));
sb.append(", flags=[").append(InsetsSource.flagsToString(mFlags)).append("]");
if (mInsetsSize != null) {
@@ -244,9 +242,7 @@ public class InsetsFrameProvider implements Parcelable {
}
public InsetsFrameProvider(Parcel in) {
- mOwner = in.readStrongBinder();
- mIndex = in.readInt();
- mType = in.readInt();
+ mId = in.readInt();
mSource = in.readInt();
mFlags = in.readInt();
mInsetsSize = in.readTypedObject(Insets.CREATOR);
@@ -256,9 +252,7 @@ public class InsetsFrameProvider implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeStrongBinder(mOwner);
- out.writeInt(mIndex);
- out.writeInt(mType);
+ out.writeInt(mId);
out.writeInt(mSource);
out.writeInt(mFlags);
out.writeTypedObject(mInsetsSize, flags);
@@ -267,7 +261,7 @@ public class InsetsFrameProvider implements Parcelable {
}
public boolean idEquals(InsetsFrameProvider o) {
- return Objects.equals(mOwner, o.mOwner) && mIndex == o.mIndex && mType == o.mType;
+ return mId == o.mId;
}
@Override
@@ -279,8 +273,7 @@ public class InsetsFrameProvider implements Parcelable {
return false;
}
final InsetsFrameProvider other = (InsetsFrameProvider) o;
- return Objects.equals(mOwner, other.mOwner) && mIndex == other.mIndex
- && mType == other.mType && mSource == other.mSource && mFlags == other.mFlags
+ return mId == other.mId && mSource == other.mSource && mFlags == other.mFlags
&& Objects.equals(mInsetsSize, other.mInsetsSize)
&& Arrays.equals(mInsetsSizeOverrides, other.mInsetsSizeOverrides)
&& Objects.equals(mArbitraryRectangle, other.mArbitraryRectangle);
@@ -288,7 +281,7 @@ public class InsetsFrameProvider implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mOwner, mIndex, mType, mSource, mFlags, mInsetsSize,
+ return Objects.hash(mId, mSource, mFlags, mInsetsSize,
Arrays.hashCode(mInsetsSizeOverrides), mArbitraryRectangle);
}
@@ -319,7 +312,7 @@ public class InsetsFrameProvider implements Parcelable {
protected InsetsSizeOverride(Parcel in) {
mWindowType = in.readInt();
- mInsetsSize = in.readParcelable(null, Insets.class);
+ mInsetsSize = in.readTypedObject(Insets.CREATOR);
}
public InsetsSizeOverride(int windowType, Insets insetsSize) {
@@ -354,7 +347,7 @@ public class InsetsFrameProvider implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mWindowType);
- out.writeParcelable(mInsetsSize, flags);
+ out.writeTypedObject(mInsetsSize, flags);
}
@Override
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index bd48771ec4b3..114f4ed04ee6 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -271,7 +271,7 @@ public class InsetsSource implements Parcelable {
* @param index An owner may have multiple sources with the same type. For example, the system
* server might have multiple display cutout sources. This is used to identify
* which one is which. The value must be in a range of [0, 2047].
- * @param type The {@link WindowInsets.Type.InsetsType type} of the source.
+ * @param type The {@link InsetsType type} of the source.
* @return a unique integer as the identifier.
*/
public static int createId(Object owner, @IntRange(from = 0, to = 2047) int index,
@@ -282,11 +282,29 @@ public class InsetsSource implements Parcelable {
// owner takes top 16 bits;
// index takes 11 bits since the 6th bit;
// type takes bottom 5 bits.
- return (((owner != null ? owner.hashCode() : 1) % (1 << 16)) << 16)
+ return ((System.identityHashCode(owner) % (1 << 16)) << 16)
+ (index << 5)
+ WindowInsets.Type.indexOf(type);
}
+ /**
+ * Gets the index from the ID.
+ *
+ * @see #createId(Object, int, int)
+ */
+ public static int getIndex(int id) {
+ return (id % (1 << 16)) >> 5;
+ }
+
+ /**
+ * Gets the {@link InsetsType} from the ID.
+ *
+ * @see #createId(Object, int, int)
+ */
+ public static int getType(int id) {
+ return 1 << (id % 32);
+ }
+
public static String flagsToString(@Flags int flags) {
final StringJoiner joiner = new StringJoiner(" ");
if ((flags & FLAG_SUPPRESS_SCRIM) != 0) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8f20e2d044ac..153bfde07758 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -11325,7 +11325,7 @@ public final class ViewRootImpl implements ViewParent,
// to sync the same frame in the same BBQ. That shouldn't be possible, but
// if it did happen, invoke markSyncReady so the active SSG doesn't get
// stuck.
- Log.e(mTag, "Unable to syncNextTransaction. Possibly something else is"
+ Log.w(mTag, "Unable to syncNextTransaction. Possibly something else is"
+ " trying to sync?");
surfaceSyncGroup.markSyncReady();
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index f7b7d3387938..e39b3a182b28 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,7 +16,6 @@
package android.view.autofill;
-import static android.Manifest.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS;
import static android.service.autofill.FillRequest.FLAG_IME_SHOWING;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
@@ -30,7 +29,6 @@ import static android.view.autofill.Helper.sVerbose;
import static android.view.autofill.Helper.toList;
import android.accessibilityservice.AccessibilityServiceInfo;
-import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -52,21 +50,16 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.metrics.LogMaker;
-import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
-import android.os.ICancellationSignal;
import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.AutofillService;
-import android.service.autofill.FillCallback;
import android.service.autofill.FillEventHistory;
-import android.service.autofill.IFillCallback;
import android.service.autofill.UserData;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -87,7 +80,6 @@ import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityWindowInfo;
-import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InputMethodManager;
import android.widget.CheckBox;
import android.widget.DatePicker;
@@ -187,12 +179,6 @@ import sun.misc.Cleaner;
* shows an autofill save UI if the value of savable views have changed. If the user selects the
* option to Save, the current value of the views is then sent to the autofill service.
*
- * <p>There is another choice for the application to provide it's datasets to the Autofill framework
- * by setting an {@link AutofillRequestCallback} through
- * {@link #setAutofillRequestCallback(Executor, AutofillRequestCallback)}. The application can use
- * its callback instead of the default {@link AutofillService}. See
- * {@link AutofillRequestCallback} for more details.
- *
* <h3 id="additional-notes">Additional notes</h3>
*
* <p>It is safe to call <code>AutofillManager</code> methods from any thread.
@@ -326,7 +312,6 @@ public final class AutofillManager {
/** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2;
/** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4;
/** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY = 0x8;
- /** @hide */ public static final int FLAG_ENABLED_CLIENT_SUGGESTIONS = 0x20;
// NOTE: flag below is used by the session start receiver only, hence it can have values above
/** @hide */ public static final int RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1;
@@ -653,11 +638,6 @@ public final class AutofillManager {
@GuardedBy("mLock")
private boolean mEnabledForAugmentedAutofillOnly;
- @GuardedBy("mLock")
- @Nullable private AutofillRequestCallback mAutofillRequestCallback;
- @GuardedBy("mLock")
- @Nullable private Executor mRequestCallbackExecutor;
-
/**
* Indicates whether there is already a field to do a fill request after
* the activity started.
@@ -2338,44 +2318,6 @@ public final class AutofillManager {
return new AutofillId(parent.getAutofillViewId(), virtualId);
}
- /**
- * Sets the client's suggestions callback for autofill.
- *
- * @see AutofillRequestCallback
- *
- * @param executor specifies the thread upon which the callbacks will be invoked.
- * @param callback which handles autofill request to provide client's suggestions.
- *
- * @hide
- */
- @TestApi
- @RequiresPermission(PROVIDE_OWN_AUTOFILL_SUGGESTIONS)
- public void setAutofillRequestCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull AutofillRequestCallback callback) {
- if (mContext.checkSelfPermission(PROVIDE_OWN_AUTOFILL_SUGGESTIONS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires PROVIDE_OWN_AUTOFILL_SUGGESTIONS permission!");
- }
-
- synchronized (mLock) {
- mRequestCallbackExecutor = executor;
- mAutofillRequestCallback = callback;
- }
- }
-
- /**
- * clears the client's suggestions callback for autofill.
- *
- * @hide
- */
- @TestApi
- public void clearAutofillRequestCallback() {
- synchronized (mLock) {
- mRequestCallbackExecutor = null;
- mAutofillRequestCallback = null;
- }
- }
-
@GuardedBy("mLock")
private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
@NonNull AutofillValue value, int flags) {
@@ -2436,13 +2378,6 @@ public final class AutofillManager {
}
}
- if (mAutofillRequestCallback != null) {
- if (sDebug) {
- Log.d(TAG, "startSession with the client suggestions provider");
- }
- flags |= FLAG_ENABLED_CLIENT_SUGGESTIONS;
- }
-
mService.startSession(client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, clientActivity,
@@ -2796,28 +2731,6 @@ public final class AutofillManager {
}
}
- private void onFillRequest(InlineSuggestionsRequest request,
- CancellationSignal cancellationSignal, FillCallback callback) {
- final AutofillRequestCallback autofillRequestCallback;
- final Executor executor;
- synchronized (mLock) {
- autofillRequestCallback = mAutofillRequestCallback;
- executor = mRequestCallbackExecutor;
- }
- if (autofillRequestCallback != null && executor != null) {
- final long ident = Binder.clearCallingIdentity();
- try {
- executor.execute(() ->
- autofillRequestCallback.onFillRequest(
- request, cancellationSignal, callback));
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- } else {
- callback.onSuccess(null);
- }
- }
-
/** @hide */
public static final int SET_STATE_FLAG_ENABLED = 0x01;
/** @hide */
@@ -4374,23 +4287,6 @@ public final class AutofillManager {
}
@Override
- public void requestFillFromClient(int id, InlineSuggestionsRequest request,
- IFillCallback callback) {
- final AutofillManager afm = mAfm.get();
- if (afm != null) {
- ICancellationSignal transport = CancellationSignal.createTransport();
- try {
- callback.onCancellable(transport);
- } catch (RemoteException e) {
- Slog.w(TAG, "Error requesting a cancellation", e);
- }
-
- afm.onFillRequest(request, CancellationSignal.fromTransport(transport),
- new FillCallback(callback, id));
- }
- }
-
- @Override
public void notifyFillDialogTriggerIds(List<AutofillId> ids) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
diff --git a/core/java/android/view/autofill/AutofillRequestCallback.java b/core/java/android/view/autofill/AutofillRequestCallback.java
deleted file mode 100644
index 10a088b4ebfa..000000000000
--- a/core/java/android/view/autofill/AutofillRequestCallback.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.autofill;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.TestApi;
-import android.os.CancellationSignal;
-import android.service.autofill.FillCallback;
-import android.view.inputmethod.InlineSuggestionsRequest;
-
-/**
- * <p>This class is used to provide some input suggestions to the Autofill framework.
- *
- * <P>When the user is requested to input something, Autofill will try to query input suggestions
- * for the user choosing. If the application want to provide some internal input suggestions,
- * implements this callback and register via
- * {@link AutofillManager#setAutofillRequestCallback(java.util.concurrent.Executor,
- * AutofillRequestCallback)}. Autofill will callback the
- * {@link #onFillRequest(InlineSuggestionsRequest, CancellationSignal, FillCallback)} to request
- * input suggestions.
- *
- * <P>To make sure the callback to take effect, must register before the autofill session starts.
- * If the autofill session is started, calls {@link AutofillManager#cancel()} to finish current
- * session, and then the callback will be used at the next restarted session.
- *
- * <P>To create a {@link android.service.autofill.FillResponse}, application should fetch
- * {@link AutofillId}s from its view structure. Below is an example:
- * <pre class="prettyprint">
- * AutofillId usernameId = findViewById(R.id.username).getAutofillId();
- * AutofillId passwordId = findViewById(R.id.password).getAutofillId();
- * </pre>
- * To learn more about creating a {@link android.service.autofill.FillResponse}, read
- * <a href="/guide/topics/text/autofill-services#fill">Fill out client views</a>.
- *
- * <P>To fallback to the default {@link android.service.autofill.AutofillService}, just respond
- * a null of the {@link android.service.autofill.FillResponse}. And then Autofill will do a fill
- * request with the default {@link android.service.autofill.AutofillService}. Or clear the callback
- * from {@link AutofillManager} via {@link AutofillManager#clearAutofillRequestCallback()}. If the
- * client would like to keep no suggestions for the field, respond with an empty
- * {@link android.service.autofill.FillResponse} which has no dataset.
- *
- * <P>IMPORTANT: This should not be used for displaying anything other than input suggestions, or
- * the keyboard may choose to block your app from the inline strip.
- *
- * @hide
- */
-@TestApi
-public interface AutofillRequestCallback {
- /**
- * Called by the Android system to decide if a screen can be autofilled by the callback.
- *
- * @param inlineSuggestionsRequest the {@link InlineSuggestionsRequest request} to handle if
- * currently inline suggestions are supported and can be displayed.
- * @param cancellationSignal signal for observing cancellation requests. The system will use
- * this to notify you that the fill result is no longer needed and you should stop
- * handling this fill request in order to save resources.
- * @param callback object used to notify the result of the request.
- */
- void onFillRequest(@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
- @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
-}
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 2e5967cc32d1..51afe4cf784d 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -24,11 +24,9 @@ import android.content.Intent;
import android.content.IntentSender;
import android.graphics.Rect;
import android.os.IBinder;
-import android.service.autofill.IFillCallback;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutofillWindowPresenter;
-import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.KeyEvent;
import com.android.internal.os.IResultReceiver;
@@ -144,12 +142,6 @@ oneway interface IAutoFillManagerClient {
void requestShowSoftInput(in AutofillId id);
/**
- * Requests to determine if a screen can be autofilled by the client app.
- */
- void requestFillFromClient(int id, in InlineSuggestionsRequest request,
- in IFillCallback callback);
-
- /**
* Notifies autofill ids that require to show the fill dialog.
*/
void notifyFillDialogTriggerIds(in List<AutofillId> ids);
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index 77a2b5b877be..581feca2de55 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -112,22 +112,6 @@ public final class InlineSuggestionsRequest implements Parcelable {
private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
/**
- * Whether the IME supports inline suggestions from the default Autofill service that
- * provides the input view.
- *
- * Note: The default value is {@code true}.
- */
- private boolean mServiceSupported;
-
- /**
- * Whether the IME supports inline suggestions from the application that provides the
- * input view.
- *
- * Note: The default value is {@code true}.
- */
- private boolean mClientSupported;
-
- /**
* @hide
* @see {@link #mHostInputToken}.
*/
@@ -221,15 +205,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
return Bundle.EMPTY;
}
- private static boolean defaultServiceSupported() {
- return true;
- }
-
- private static boolean defaultClientSupported() {
- return true;
- }
-
- /** @hide */
+ /**
+ * @hide
+ */
abstract static class BaseBuilder {
abstract Builder setInlinePresentationSpecs(
@NonNull List<android.widget.inline.InlinePresentationSpec> specs);
@@ -241,25 +219,14 @@ public final class InlineSuggestionsRequest implements Parcelable {
abstract Builder setHostDisplayId(int value);
}
- /** @hide */
- public boolean isServiceSupported() {
- return mServiceSupported;
- }
-
- /** @hide */
- public boolean isClientSupported() {
- return mClientSupported;
- }
-
-
- // Code below generated by codegen v1.0.22.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+ // $ codegen $ANDROID_BUILD_TOP/./frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -275,9 +242,7 @@ public final class InlineSuggestionsRequest implements Parcelable {
@NonNull Bundle extras,
@Nullable IBinder hostInputToken,
int hostDisplayId,
- @Nullable InlinePresentationSpec inlineTooltipPresentationSpec,
- boolean serviceSupported,
- boolean clientSupported) {
+ @Nullable InlinePresentationSpec inlineTooltipPresentationSpec) {
this.mMaxSuggestionCount = maxSuggestionCount;
this.mInlinePresentationSpecs = inlinePresentationSpecs;
com.android.internal.util.AnnotationValidations.validate(
@@ -294,8 +259,6 @@ public final class InlineSuggestionsRequest implements Parcelable {
this.mHostInputToken = hostInputToken;
this.mHostDisplayId = hostDisplayId;
this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
- this.mServiceSupported = serviceSupported;
- this.mClientSupported = clientSupported;
onConstructed();
}
@@ -379,9 +342,7 @@ public final class InlineSuggestionsRequest implements Parcelable {
}
/**
- * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
- *
- * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)
+ * Specifies the UI specification for the inline suggestion tooltip in the response.
*/
@DataClass.Generated.Member
public @Nullable InlinePresentationSpec getInlineTooltipPresentationSpec() {
@@ -402,9 +363,7 @@ public final class InlineSuggestionsRequest implements Parcelable {
"extras = " + mExtras + ", " +
"hostInputToken = " + mHostInputToken + ", " +
"hostDisplayId = " + mHostDisplayId + ", " +
- "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec + ", " +
- "serviceSupported = " + mServiceSupported + ", " +
- "clientSupported = " + mClientSupported +
+ "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec +
" }";
}
@@ -428,9 +387,7 @@ public final class InlineSuggestionsRequest implements Parcelable {
&& extrasEquals(that.mExtras)
&& java.util.Objects.equals(mHostInputToken, that.mHostInputToken)
&& mHostDisplayId == that.mHostDisplayId
- && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec)
- && mServiceSupported == that.mServiceSupported
- && mClientSupported == that.mClientSupported;
+ && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec);
}
@Override
@@ -448,8 +405,6 @@ public final class InlineSuggestionsRequest implements Parcelable {
_hash = 31 * _hash + java.util.Objects.hashCode(mHostInputToken);
_hash = 31 * _hash + mHostDisplayId;
_hash = 31 * _hash + java.util.Objects.hashCode(mInlineTooltipPresentationSpec);
- _hash = 31 * _hash + Boolean.hashCode(mServiceSupported);
- _hash = 31 * _hash + Boolean.hashCode(mClientSupported);
return _hash;
}
@@ -460,8 +415,6 @@ public final class InlineSuggestionsRequest implements Parcelable {
// void parcelFieldName(Parcel dest, int flags) { ... }
int flg = 0;
- if (mServiceSupported) flg |= 0x100;
- if (mClientSupported) flg |= 0x200;
if (mHostInputToken != null) flg |= 0x20;
if (mInlineTooltipPresentationSpec != null) flg |= 0x80;
dest.writeInt(flg);
@@ -487,11 +440,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
// static FieldType unparcelFieldName(Parcel in) { ... }
int flg = in.readInt();
- boolean serviceSupported = (flg & 0x100) != 0;
- boolean clientSupported = (flg & 0x200) != 0;
int maxSuggestionCount = in.readInt();
List<InlinePresentationSpec> inlinePresentationSpecs = new ArrayList<>();
- in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader(), android.widget.inline.InlinePresentationSpec.class);
+ in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader());
String hostPackageName = in.readString();
LocaleList supportedLocales = (LocaleList) in.readTypedObject(LocaleList.CREATOR);
Bundle extras = in.readBundle();
@@ -515,8 +466,6 @@ public final class InlineSuggestionsRequest implements Parcelable {
this.mHostInputToken = hostInputToken;
this.mHostDisplayId = hostDisplayId;
this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
- this.mServiceSupported = serviceSupported;
- this.mClientSupported = clientSupported;
onConstructed();
}
@@ -550,8 +499,6 @@ public final class InlineSuggestionsRequest implements Parcelable {
private @Nullable IBinder mHostInputToken;
private int mHostDisplayId;
private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
- private boolean mServiceSupported;
- private boolean mClientSupported;
private long mBuilderFieldsSet = 0L;
@@ -684,9 +631,7 @@ public final class InlineSuggestionsRequest implements Parcelable {
}
/**
- * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
- *
- * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)s
+ * Specifies the UI specification for the inline suggestion tooltip in the response.
*/
@DataClass.Generated.Member
public @NonNull Builder setInlineTooltipPresentationSpec(@NonNull InlinePresentationSpec value) {
@@ -696,44 +641,10 @@ public final class InlineSuggestionsRequest implements Parcelable {
return this;
}
- /**
- * Whether the IME supports inline suggestions from the default Autofill service that
- * provides the input view.
- *
- * Note: The default value is {@code true}.
- *
- * @hide
- */
- @TestApi
- @DataClass.Generated.Member
- public @NonNull Builder setServiceSupported(boolean value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x100;
- mServiceSupported = value;
- return this;
- }
-
- /**
- * Whether the IME supports inline suggestions from the application that provides the
- * input view.
- *
- * Note: The default value is {@code true}.
- *
- * @hide
- */
- @TestApi
- @DataClass.Generated.Member
- public @NonNull Builder setClientSupported(boolean value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x200;
- mClientSupported = value;
- return this;
- }
-
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull InlineSuggestionsRequest build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x400; // Mark builder used
+ mBuilderFieldsSet |= 0x100; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mMaxSuggestionCount = defaultMaxSuggestionCount();
@@ -756,12 +667,6 @@ public final class InlineSuggestionsRequest implements Parcelable {
if ((mBuilderFieldsSet & 0x80) == 0) {
mInlineTooltipPresentationSpec = defaultInlineTooltipPresentationSpec();
}
- if ((mBuilderFieldsSet & 0x100) == 0) {
- mServiceSupported = defaultServiceSupported();
- }
- if ((mBuilderFieldsSet & 0x200) == 0) {
- mClientSupported = defaultClientSupported();
- }
InlineSuggestionsRequest o = new InlineSuggestionsRequest(
mMaxSuggestionCount,
mInlinePresentationSpecs,
@@ -770,14 +675,12 @@ public final class InlineSuggestionsRequest implements Parcelable {
mExtras,
mHostInputToken,
mHostDisplayId,
- mInlineTooltipPresentationSpec,
- mServiceSupported,
- mClientSupported);
+ mInlineTooltipPresentationSpec);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x400) != 0) {
+ if ((mBuilderFieldsSet & 0x100) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -785,10 +688,10 @@ public final class InlineSuggestionsRequest implements Parcelable {
}
@DataClass.Generated(
- time = 1615798784918L,
- codegenVersion = "1.0.22",
+ time = 1682382296877L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
- inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate boolean mServiceSupported\nprivate boolean mClientSupported\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nprivate static boolean defaultServiceSupported()\nprivate static boolean defaultClientSupported()\npublic boolean isServiceSupported()\npublic boolean isClientSupported()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
index 95451a966055..fa7f577dadb8 100644
--- a/core/java/android/window/ScreenCapture.java
+++ b/core/java/android/window/ScreenCapture.java
@@ -198,17 +198,21 @@ public class ScreenCapture {
* Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
*
* @param hardwareBuffer The existing HardwareBuffer object
- * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
+ * @param dataspace Dataspace describing the content.
+ * {@see android.hardware.DataSpace}
* @param containsSecureLayers Indicates whether this graphic buffer contains captured
* contents of secure layers, in which case the screenshot
* should not be persisted.
* @param containsHdrLayers Indicates whether this graphic buffer contains HDR content.
*/
private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
- int namedColorSpace, boolean containsSecureLayers, boolean containsHdrLayers) {
- ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
+ int dataspace, boolean containsSecureLayers, boolean containsHdrLayers) {
+ ColorSpace colorSpace = ColorSpace.getFromDataSpace(dataspace);
return new ScreenshotHardwareBuffer(
- hardwareBuffer, colorSpace, containsSecureLayers, containsHdrLayers);
+ hardwareBuffer,
+ colorSpace != null ? colorSpace : ColorSpace.get(ColorSpace.Named.SRGB),
+ containsSecureLayers,
+ containsHdrLayers);
}
public ColorSpace getColorSpace() {
@@ -271,8 +275,8 @@ public class ScreenCapture {
public final boolean mAllowProtected;
public final long mUid;
public final boolean mGrayscale;
-
final SurfaceControl[] mExcludeLayers;
+ public final boolean mHintForSeamlessTransition;
private CaptureArgs(CaptureArgs.Builder<? extends CaptureArgs.Builder<?>> builder) {
mPixelFormat = builder.mPixelFormat;
@@ -284,6 +288,7 @@ public class ScreenCapture {
mUid = builder.mUid;
mGrayscale = builder.mGrayscale;
mExcludeLayers = builder.mExcludeLayers;
+ mHintForSeamlessTransition = builder.mHintForSeamlessTransition;
}
private CaptureArgs(Parcel in) {
@@ -305,6 +310,7 @@ public class ScreenCapture {
} else {
mExcludeLayers = null;
}
+ mHintForSeamlessTransition = in.readBoolean();
}
/** Release any layers if set using {@link Builder#setExcludeLayers(SurfaceControl[])}. */
@@ -352,6 +358,7 @@ public class ScreenCapture {
private long mUid = -1;
private boolean mGrayscale;
private SurfaceControl[] mExcludeLayers;
+ private boolean mHintForSeamlessTransition;
/**
* Construct a new {@link CaptureArgs} with the set parameters. The builder remains
@@ -449,6 +456,21 @@ public class ScreenCapture {
}
/**
+ * Set whether the screenshot will be used in a system animation.
+ * This hint is used for picking the "best" colorspace for the screenshot, in particular
+ * for mixing HDR and SDR content.
+ * E.g., hintForSeamlessTransition is false, then a colorspace suitable for file
+ * encoding, such as BT2100, may be chosen. Otherwise, then the display's color space
+ * would be chosen, with the possibility of having an extended brightness range. This
+ * is important for screenshots that are directly re-routed to a SurfaceControl in
+ * order to preserve accurate colors.
+ */
+ public T setHintForSeamlessTransition(boolean hintForSeamlessTransition) {
+ mHintForSeamlessTransition = hintForSeamlessTransition;
+ return getThis();
+ }
+
+ /**
* Each sub class should return itself to allow the builder to chain properly
*/
T getThis() {
@@ -471,7 +493,6 @@ public class ScreenCapture {
dest.writeBoolean(mAllowProtected);
dest.writeLong(mUid);
dest.writeBoolean(mGrayscale);
-
if (mExcludeLayers != null) {
dest.writeInt(mExcludeLayers.length);
for (SurfaceControl excludeLayer : mExcludeLayers) {
@@ -480,6 +501,7 @@ public class ScreenCapture {
} else {
dest.writeInt(0);
}
+ dest.writeBoolean(mHintForSeamlessTransition);
}
public static final Parcelable.Creator<CaptureArgs> CREATOR =
@@ -627,6 +649,7 @@ public class ScreenCapture {
setUid(args.mUid);
setGrayscale(args.mGrayscale);
setExcludeLayers(args.mExcludeLayers);
+ setHintForSeamlessTransition(args.mHintForSeamlessTransition);
}
public Builder(SurfaceControl layer) {
diff --git a/core/java/android/window/StartingWindowRemovalInfo.java b/core/java/android/window/StartingWindowRemovalInfo.java
index 518123600b9a..6999e5bdc527 100644
--- a/core/java/android/window/StartingWindowRemovalInfo.java
+++ b/core/java/android/window/StartingWindowRemovalInfo.java
@@ -16,6 +16,7 @@
package android.window;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
@@ -23,6 +24,9 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.view.SurfaceControl;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Information when removing a starting window of a particular task.
* @hide
@@ -55,11 +59,28 @@ public final class StartingWindowRemovalInfo implements Parcelable {
*/
public boolean playRevealAnimation;
+ /** The mode is no need to defer removing the starting window for IME */
+ public static final int DEFER_MODE_NONE = 0;
+
+ /** The mode to defer removing the starting window until IME has drawn */
+ public static final int DEFER_MODE_NORMAL = 1;
+
+ /** The mode to defer the starting window removal until IME drawn and finished the rotation */
+ public static final int DEFER_MODE_ROTATION = 2;
+
+ @IntDef(prefix = { "DEFER_MODE_" }, value = {
+ DEFER_MODE_NONE,
+ DEFER_MODE_NORMAL,
+ DEFER_MODE_ROTATION,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DeferMode {}
+
/**
* Whether need to defer removing the starting window for IME.
* @hide
*/
- public boolean deferRemoveForIme;
+ public @DeferMode int deferRemoveForImeMode;
/**
* The rounded corner radius
@@ -95,7 +116,7 @@ public final class StartingWindowRemovalInfo implements Parcelable {
windowAnimationLeash = source.readTypedObject(SurfaceControl.CREATOR);
mainFrame = source.readTypedObject(Rect.CREATOR);
playRevealAnimation = source.readBoolean();
- deferRemoveForIme = source.readBoolean();
+ deferRemoveForImeMode = source.readInt();
roundedCornerRadius = source.readFloat();
windowlessSurface = source.readBoolean();
removeImmediately = source.readBoolean();
@@ -107,7 +128,7 @@ public final class StartingWindowRemovalInfo implements Parcelable {
dest.writeTypedObject(windowAnimationLeash, flags);
dest.writeTypedObject(mainFrame, flags);
dest.writeBoolean(playRevealAnimation);
- dest.writeBoolean(deferRemoveForIme);
+ dest.writeInt(deferRemoveForImeMode);
dest.writeFloat(roundedCornerRadius);
dest.writeBoolean(windowlessSurface);
dest.writeBoolean(removeImmediately);
@@ -119,7 +140,7 @@ public final class StartingWindowRemovalInfo implements Parcelable {
+ " frame=" + mainFrame
+ " playRevealAnimation=" + playRevealAnimation
+ " roundedCornerRadius=" + roundedCornerRadius
- + " deferRemoveForIme=" + deferRemoveForIme
+ + " deferRemoveForImeMode=" + deferRemoveForImeMode
+ " windowlessSurface=" + windowlessSurface
+ " removeImmediately=" + removeImmediately + "}";
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 628fc3140ee8..c0370cc5517d 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -21,6 +21,7 @@ import static android.app.ActivityOptions.ANIM_CUSTOM;
import static android.app.ActivityOptions.ANIM_FROM_STYLE;
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.ActivityOptions.ANIM_SCALE_UP;
+import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
@@ -1067,6 +1068,11 @@ public final class TransitionInfo implements Parcelable {
return options;
}
+ public static AnimationOptions makeSceneTransitionAnimOptions() {
+ AnimationOptions options = new AnimationOptions(ANIM_SCENE_TRANSITION);
+ return options;
+ }
+
public int getType() {
return mType;
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index 853fe2f114f7..86c2893c9fab 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -76,7 +76,7 @@ public class SystemUiSystemPropertiesFlags {
/** Gating the removal of sorting-notifications-by-interruptiveness. */
public static final Flag NO_SORT_BY_INTERRUPTIVENESS =
- devFlag("persist.sysui.notification.no_sort_by_interruptiveness");
+ releasedFlag("persist.sysui.notification.no_sort_by_interruptiveness");
/** Gating the logging of DND state change events. */
public static final Flag LOG_DND_STATE_EVENTS =
@@ -115,7 +115,7 @@ public class SystemUiSystemPropertiesFlags {
}
/**
- * Creates a flag that is enabled by default in debuggable builds.
+ * Creates a flag that is disabled by default in debuggable builds.
* It can be enabled by setting this flag's SystemProperty to 1.
*
* This flag is ALWAYS disabled in release builds.
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index fbad4b9fd377..a554d0e77410 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -731,7 +731,7 @@ public class LockPatternUtils {
return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_AUTO_PIN_CONFIRMATION,
FLAG_ENABLE_AUTO_PIN_CONFIRMATION,
- /* defaultValue= */ false);
+ /* defaultValue= */ true);
}
/** Returns if the given quality maps to an alphabetic password */
diff --git a/core/jni/android_window_ScreenCapture.cpp b/core/jni/android_window_ScreenCapture.cpp
index 1b67a0da57e1..986dbe9a204c 100644
--- a/core/jni/android_window_ScreenCapture.cpp
+++ b/core/jni/android_window_ScreenCapture.cpp
@@ -46,6 +46,7 @@ static struct {
jfieldID uid;
jfieldID grayscale;
jmethodID getNativeExcludeLayers;
+ jfieldID hintForSeamlessTransition;
} gCaptureArgsClassInfo;
static struct {
@@ -69,23 +70,6 @@ static struct {
jmethodID builder;
} gScreenshotHardwareBufferClassInfo;
-enum JNamedColorSpace : jint {
- // ColorSpace.Named.SRGB.ordinal() = 0;
- SRGB = 0,
-
- // ColorSpace.Named.DISPLAY_P3.ordinal() = 7;
- DISPLAY_P3 = 7,
-};
-
-constexpr jint fromDataspaceToNamedColorSpaceValue(const ui::Dataspace dataspace) {
- switch (dataspace) {
- case ui::Dataspace::DISPLAY_P3:
- return JNamedColorSpace::DISPLAY_P3;
- default:
- return JNamedColorSpace::SRGB;
- }
-}
-
static void checkAndClearException(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
ALOGE("An exception was thrown by callback '%s'.", methodName);
@@ -119,12 +103,11 @@ public:
captureResults.fenceResult.value()->waitForever(LOG_TAG);
jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
env, captureResults.buffer->toAHardwareBuffer());
- const jint namedColorSpace =
- fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
jobject screenshotHardwareBuffer =
env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
gScreenshotHardwareBufferClassInfo.builder,
- jhardwareBuffer, namedColorSpace,
+ jhardwareBuffer,
+ static_cast<jint>(captureResults.capturedDataspace),
captureResults.capturedSecureLayers,
captureResults.capturedHdrLayers);
checkAndClearException(env, "builder");
@@ -185,6 +168,9 @@ static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs&
captureArgs.excludeHandles.emplace(excludeObject->getHandle());
}
}
+ captureArgs.hintForSeamlessTransition =
+ env->GetBooleanField(captureArgsObject,
+ gCaptureArgsClassInfo.hintForSeamlessTransition);
}
static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
@@ -318,9 +304,10 @@ int register_android_window_ScreenCapture(JNIEnv* env) {
GetFieldIDOrDie(env, captureArgsClazz, "mAllowProtected", "Z");
gCaptureArgsClassInfo.uid = GetFieldIDOrDie(env, captureArgsClazz, "mUid", "J");
gCaptureArgsClassInfo.grayscale = GetFieldIDOrDie(env, captureArgsClazz, "mGrayscale", "Z");
-
gCaptureArgsClassInfo.getNativeExcludeLayers =
GetMethodIDOrDie(env, captureArgsClazz, "getNativeExcludeLayers", "()[J");
+ gCaptureArgsClassInfo.hintForSeamlessTransition =
+ GetFieldIDOrDie(env, captureArgsClazz, "mHintForSeamlessTransition", "Z");
jclass displayCaptureArgsClazz =
FindClassOrDie(env, "android/window/ScreenCapture$DisplayCaptureArgs");
diff --git a/core/proto/android/companion/telecom.proto b/core/proto/android/companion/telecom.proto
index 3a9e5eeb4877..02ba7c5e39ff 100644
--- a/core/proto/android/companion/telecom.proto
+++ b/core/proto/android/companion/telecom.proto
@@ -25,7 +25,7 @@ message Telecom {
// Next index: 6
message Call {
// UUID representing this call
- int64 id = 1;
+ string id = 1;
message Origin {
// Caller's name and/or phone number; what a user would see displayed when receiving an
@@ -48,22 +48,23 @@ message Telecom {
}
Status status = 3;
- enum Control {
- UNKNOWN_CONTROL = 0;
- ACCEPT = 1;
- REJECT = 2;
- SILENCE = 3;
- MUTE = 4;
- UNMUTE = 5;
- END = 6;
- PUT_ON_HOLD = 7;
- TAKE_OFF_HOLD = 8;
- REJECT_AND_BLOCK = 9;
- IGNORE = 10;
- }
repeated Control controls = 4;
}
+ enum Control {
+ UNKNOWN_CONTROL = 0;
+ ACCEPT = 1;
+ REJECT = 2;
+ SILENCE = 3;
+ MUTE = 4;
+ UNMUTE = 5;
+ END = 6;
+ PUT_ON_HOLD = 7;
+ TAKE_OFF_HOLD = 8;
+ REJECT_AND_BLOCK = 9;
+ IGNORE = 10;
+ }
+
// The list of active calls.
repeated Call calls = 1;
// The list of requested calls or call changes.
diff --git a/core/res/res/drawable-hdpi/pointer_all_scroll.png b/core/res/res/drawable-hdpi/pointer_all_scroll.png
index 095aadce579d..4af84c3e9202 100644
--- a/core/res/res/drawable-hdpi/pointer_all_scroll.png
+++ b/core/res/res/drawable-hdpi/pointer_all_scroll.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_horizontal_double_arrow.png b/core/res/res/drawable-hdpi/pointer_horizontal_double_arrow.png
index 9388f162b17e..c4018c83da86 100644
--- a/core/res/res/drawable-hdpi/pointer_horizontal_double_arrow.png
+++ b/core/res/res/drawable-hdpi/pointer_horizontal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_top_left_diagonal_double_arrow.png b/core/res/res/drawable-hdpi/pointer_top_left_diagonal_double_arrow.png
index ab52bffd9de5..58bb0d4cb2c9 100644
--- a/core/res/res/drawable-hdpi/pointer_top_left_diagonal_double_arrow.png
+++ b/core/res/res/drawable-hdpi/pointer_top_left_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_top_right_diagonal_double_arrow.png b/core/res/res/drawable-hdpi/pointer_top_right_diagonal_double_arrow.png
index 1250d35df469..1981d41e2c34 100644
--- a/core/res/res/drawable-hdpi/pointer_top_right_diagonal_double_arrow.png
+++ b/core/res/res/drawable-hdpi/pointer_top_right_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_vertical_double_arrow.png b/core/res/res/drawable-hdpi/pointer_vertical_double_arrow.png
index 6730c7b4a365..d4ba79ad32b2 100644
--- a/core/res/res/drawable-hdpi/pointer_vertical_double_arrow.png
+++ b/core/res/res/drawable-hdpi/pointer_vertical_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_all_scroll.png b/core/res/res/drawable-mdpi/pointer_all_scroll.png
index 3db456e885d2..1b81d0aaa1ab 100644
--- a/core/res/res/drawable-mdpi/pointer_all_scroll.png
+++ b/core/res/res/drawable-mdpi/pointer_all_scroll.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_all_scroll_large.png b/core/res/res/drawable-mdpi/pointer_all_scroll_large.png
index 120e1d72d233..9e1f5c915544 100644
--- a/core/res/res/drawable-mdpi/pointer_all_scroll_large.png
+++ b/core/res/res/drawable-mdpi/pointer_all_scroll_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png b/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png
index 20f319ac5cc4..d1b3441d9117 100644
--- a/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png
+++ b/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow_large.png b/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow_large.png
index 33ef5c96ac8a..4e26371e7c7f 100644
--- a/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow_large.png
+++ b/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png b/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png
index fe7d49602aa5..34c0c6a7a804 100644
--- a/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png
+++ b/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow_large.png b/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow_large.png
index 7b2e20c9d19c..87ec1847d524 100644
--- a/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow_large.png
+++ b/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png b/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png
index 95a662017927..40b9c7e24cde 100644
--- a/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png
+++ b/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow_large.png b/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow_large.png
index 2e2904b6562d..6a85b493499c 100644
--- a/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow_large.png
+++ b/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png b/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png
index ae6bfed37812..9bd89bf3013b 100644
--- a/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png
+++ b/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_vertical_double_arrow_large.png b/core/res/res/drawable-mdpi/pointer_vertical_double_arrow_large.png
index 3beb1d1e9c8c..5a69bbc4713b 100644
--- a/core/res/res/drawable-mdpi/pointer_vertical_double_arrow_large.png
+++ b/core/res/res/drawable-mdpi/pointer_vertical_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_all_scroll.png b/core/res/res/drawable-xhdpi/pointer_all_scroll.png
index e9d05d5079be..85aa0229dc9b 100644
--- a/core/res/res/drawable-xhdpi/pointer_all_scroll.png
+++ b/core/res/res/drawable-xhdpi/pointer_all_scroll.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png b/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png
index 1fd54fb3cc9b..74483394ab71 100644
--- a/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png
index caf2a97bb7be..dd37f926edd6 100644
--- a/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png
+++ b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png
index 2f22640f99e6..9e031e85fadc 100644
--- a/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png
index a36deb3f4995..150d80d91a40 100644
--- a/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png
+++ b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png
index 6870e23ae817..bae907aca601 100644
--- a/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png
index c8d6d1f14a8a..3b23143cd44a 100644
--- a/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png
+++ b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png
index 5bfb7712f59d..a90b28628a6b 100644
--- a/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png
index 720df913f9dc..3e7f850fbe70 100644
--- a/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png
+++ b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png
index 82b30d1fedc2..090e3cac9cac 100644
--- a/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_all_scroll.png b/core/res/res/drawable-xxhdpi/pointer_all_scroll.png
index 808143aeff08..92aae724fdb3 100644
--- a/core/res/res/drawable-xxhdpi/pointer_all_scroll.png
+++ b/core/res/res/drawable-xxhdpi/pointer_all_scroll.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_horizontal_double_arrow.png b/core/res/res/drawable-xxhdpi/pointer_horizontal_double_arrow.png
index 677ccadbb26a..b1e2509a1e23 100644
--- a/core/res/res/drawable-xxhdpi/pointer_horizontal_double_arrow.png
+++ b/core/res/res/drawable-xxhdpi/pointer_horizontal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_top_left_diagonal_double_arrow.png b/core/res/res/drawable-xxhdpi/pointer_top_left_diagonal_double_arrow.png
index e01aa649780c..2d1217c58684 100644
--- a/core/res/res/drawable-xxhdpi/pointer_top_left_diagonal_double_arrow.png
+++ b/core/res/res/drawable-xxhdpi/pointer_top_left_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_top_right_diagonal_double_arrow.png b/core/res/res/drawable-xxhdpi/pointer_top_right_diagonal_double_arrow.png
index e947e0ea6f14..a99fb24cb849 100644
--- a/core/res/res/drawable-xxhdpi/pointer_top_right_diagonal_double_arrow.png
+++ b/core/res/res/drawable-xxhdpi/pointer_top_right_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_vertical_double_arrow.png b/core/res/res/drawable-xxhdpi/pointer_vertical_double_arrow.png
index c867247c08f4..1f065fa8f632 100644
--- a/core/res/res/drawable-xxhdpi/pointer_vertical_double_arrow.png
+++ b/core/res/res/drawable-xxhdpi/pointer_vertical_double_arrow.png
Binary files differ
diff --git a/core/res/res/layout-television/user_switching_dialog.xml b/core/res/res/layout-television/user_switching_dialog.xml
deleted file mode 100644
index 72150e32c0a0..000000000000
--- a/core/res/res/layout-television/user_switching_dialog.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/message"
- style="?attr/textAppearanceListItem"
- android:layout_width="match_parent"
- android:background="@color/background_leanback_dark"
- android:textColor="@color/primary_text_leanback_dark"
- android:layout_height="match_parent"
- android:gravity="center"
- android:paddingStart="?attr/dialogPreferredPadding"
- android:paddingEnd="?attr/dialogPreferredPadding"
- android:paddingTop="24dp"
- android:paddingBottom="24dp" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7bc3ab80da99..50aec835cc31 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -991,6 +991,25 @@
<!-- Nominal White Z --> <item>1.089058</item>
</string-array>
+ <!-- The CCT closest to the white coordinates (primary) above and in SurfaceControl. -->
+ <integer name="config_displayWhiteBalanceDisplayNominalWhiteCct">6500</integer>
+
+ <!-- Range minimums corresponding to config_displayWhiteBalanceDisplaySteps. For example, if the
+ range minimums are [0, 3000] and the steps are [10, 20] then between 0 and 3000, exclusive,
+ the step between them will be 10 (i.e. 0, 10, 20, etc.) and the step between 3000 and the
+ maximum value is 20 (i.e. 3000, 3020, 3040, etc.). -->
+ <integer-array name="config_displayWhiteBalanceDisplayRangeMinimums">
+ <item>0</item>
+ </integer-array>
+
+ <!-- Steps corresponding to config_displayWhiteBalanceDisplayRangeMinimums. For example, if the
+ range minimums are [0, 3000] and the steps are [10, 20] then between 0 and 3000, exclusive,
+ the step between them will be 10 (i.e. 0, 10, 20, etc.) and the step between 3000 and the
+ maximum value is 20 (i.e. 3000, 3020, 3040, etc.). -->
+ <integer-array name="config_displayWhiteBalanceDisplaySteps">
+ <item>1</item>
+ </integer-array>
+
<!-- Boolean indicating whether light mode is allowed when DWB is turned on. -->
<bool name="config_displayWhiteBalanceLightModeAllowed">true</bool>
@@ -6396,7 +6415,7 @@
Packages can be added by OEMs in an allowlist, to prevent them from being scanned as
"stopped" during initial boot of a device, or after an OTA update. Stopped state of
an app is not changed during subsequent reboots. -->
- <bool name="config_stopSystemPackagesByDefault">false</bool>
+ <bool name="config_stopSystemPackagesByDefault">true</bool>
<!-- Whether to show weather on the lock screen by default. -->
<bool name="config_lockscreenWeatherEnabledByDefault">false</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index ad864b13b16d..bc0af12e9569 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -96,12 +96,12 @@
<!-- Width of the navigation bar when it is placed vertically on the screen in car mode -->
<dimen name="navigation_bar_width_car_mode">96dp</dimen>
<!-- Height of notification icons in the status bar -->
- <dimen name="status_bar_icon_size">18sp</dimen>
+ <dimen name="status_bar_icon_size">22dip</dimen>
<!-- Desired size of system icons in status bar. -->
- <dimen name="status_bar_system_icon_size">15sp</dimen>
+ <dimen name="status_bar_system_icon_size">15dp</dimen>
<!-- Intrinsic size of most system icons in status bar. This is the default value that
is used if a Drawable reports an intrinsic size of 0. -->
- <dimen name="status_bar_system_icon_intrinsic_size">17sp</dimen>
+ <dimen name="status_bar_system_icon_intrinsic_size">17dp</dimen>
<!-- Size of the giant number (unread count) in the notifications -->
<dimen name="status_bar_content_number_size">48sp</dimen>
<!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
@@ -330,7 +330,7 @@
<dimen name="notification_icon_circle_start">16dp</dimen>
<!-- size (width and height) of the icon in the notification header -->
- <dimen name="notification_header_icon_size_ambient">18sp</dimen>
+ <dimen name="notification_header_icon_size_ambient">18dp</dimen>
<!-- The margin before the start of the app name in the header. -->
<dimen name="notification_header_app_name_margin_start">3dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e25425d6cb18..218bbc24bbe6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3423,6 +3423,9 @@
<java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureDefault" />
<java-symbol type="array" name="config_displayWhiteBalanceDisplayPrimaries" />
<java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" />
+ <java-symbol type="integer" name="config_displayWhiteBalanceDisplayNominalWhiteCct" />
+ <java-symbol type="array" name="config_displayWhiteBalanceDisplayRangeMinimums" />
+ <java-symbol type="array" name="config_displayWhiteBalanceDisplaySteps" />
<java-symbol type="bool" name="config_displayWhiteBalanceLightModeAllowed" />
<java-symbol type="integer" name="config_displayWhiteBalanceTransitionTime" />
diff --git a/core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp b/core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp
index db1f7bde4b4f..187e2c137f85 100644
--- a/core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp
+++ b/core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp
@@ -77,15 +77,18 @@ static void nativeUnparcelAndVerifyWorkSource(JNIEnv* env, jobject /* obj */, jo
Parcel* parcel = nativeGetParcelData(env, wsParcel);
int32_t endMarker;
- // read WorkSource and if no error read end marker
- status_t err = ws.readFromParcel(parcel) ?: parcel->readInt32(&endMarker);
- int32_t dataAvailable = parcel->dataAvail();
-
+ status_t err = ws.readFromParcel(parcel);
if (err != OK) {
- ALOGE("WorkSource readFromParcel failed %d", err);
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ StringPrintf("WorkSource readFromParcel failed: %d", err).c_str());
+ }
+ err = parcel->readInt32(&endMarker);
+ if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ StringPrintf("Failed to read endMarker: %d", err).c_str());
}
-
// Now we have a native WorkSource object, verify it.
+ int32_t dataAvailable = parcel->dataAvail();
if (dataAvailable > 0) { // not all data read from the parcel
jniThrowException(env, "java/lang/IllegalArgumentException",
StringPrintf("WorkSource contains more data than native read (%d)",
diff --git a/core/tests/coretests/src/android/view/InsetsSourceTest.java b/core/tests/coretests/src/android/view/InsetsSourceTest.java
index 6fa8f1117343..55680abb159d 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceTest.java
@@ -227,5 +227,25 @@ public class InsetsSourceTest {
assertEquals(numTotalSources, sources.size());
}
+ @Test
+ public void testGetIndex() {
+ for (int index = 0; index < 2048; index++) {
+ for (int type = FIRST; type <= LAST; type = type << 1) {
+ final int id = InsetsSource.createId(null, index, type);
+ assertEquals(index, InsetsSource.getIndex(id));
+ }
+ }
+ }
+
+ @Test
+ public void testGetType() {
+ for (int index = 0; index < 2048; index++) {
+ for (int type = FIRST; type <= LAST; type = type << 1) {
+ final int id = InsetsSource.createId(null, index, type);
+ assertEquals(type, InsetsSource.getType(id));
+ }
+ }
+ }
+
// Parcel and equals already tested via InsetsStateTest
}
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 922dbb5fef38..43683ffad432 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -31,6 +31,7 @@
<permission name="android.permission.DUMP"/>
<permission name="android.permission.GET_APP_OPS_STATS"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.LOCATION_HARDWARE"/>
<permission name="android.permission.MANAGE_DEBUGGING"/>
<permission name="android.permission.MANAGE_GAME_MODE" />
<permission name="android.permission.MANAGE_SENSOR_PRIVACY"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 40cb7f2194e9..1f1239e3c310 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -520,6 +520,10 @@ applications that come with the platform
<permission name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
<!-- Permission required for CTS test - SatelliteManagerTest -->
<permission name="android.permission.SATELLITE_COMMUNICATION"/>
+ <!-- Permission required for GTS test - GtsAttestationVerificationDeviceSideTestCases -->
+ <permission name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE" />
+ <!-- Permission required for GTS test - GtsCredentialsTestCases -->
+ <permission name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 302c72ead52e..dd4b58eb83dc 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -40,6 +40,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
+import android.media.MediaFormat;
import android.net.Uri;
import android.os.Build;
import android.os.Trace;
@@ -914,8 +915,6 @@ public final class ImageDecoder implements AutoCloseable {
case "image/jpeg":
case "image/webp":
case "image/gif":
- case "image/heif":
- case "image/heic":
case "image/bmp":
case "image/x-ico":
case "image/vnd.wap.wbmp":
@@ -930,6 +929,9 @@ public final class ImageDecoder implements AutoCloseable {
case "image/x-pentax-pef":
case "image/x-samsung-srw":
return true;
+ case "image/heif":
+ case "image/heic":
+ return isHevcDecoderSupported();
case "image/avif":
return isP010SupportedForAV1();
default:
@@ -2067,6 +2069,28 @@ public final class ImageDecoder implements AutoCloseable {
return decodeBitmapImpl(src, null);
}
+ private static boolean sIsHevcDecoderSupported = false;
+ private static boolean sIsHevcDecoderSupportedInitialized = false;
+ private static final Object sIsHevcDecoderSupportedLock = new Object();
+
+ /*
+ * Check if HEVC decoder is supported by the device.
+ */
+ @SuppressWarnings("AndroidFrameworkCompatChange")
+ private static boolean isHevcDecoderSupported() {
+ synchronized (sIsHevcDecoderSupportedLock) {
+ if (sIsHevcDecoderSupportedInitialized) {
+ return sIsHevcDecoderSupported;
+ }
+ MediaFormat format = new MediaFormat();
+ format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_HEVC);
+ MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ sIsHevcDecoderSupported = mcl.findDecoderForFormat(format) != null;
+ sIsHevcDecoderSupportedInitialized = true;
+ return sIsHevcDecoderSupported;
+ }
+ }
+
private static boolean sIsP010SupportedForAV1 = false;
private static boolean sIsP010SupportedForHEVC = false;
private static boolean sIsP010SupportedFlagsInitialized = false;
@@ -2105,20 +2129,20 @@ public final class ImageDecoder implements AutoCloseable {
* Checks if the device supports decoding 10-bit for the given mime type.
*/
private static void checkP010SupportforAV1HEVC() {
- MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
for (MediaCodecInfo mediaCodecInfo : codecList.getCodecInfos()) {
if (mediaCodecInfo.isEncoder()) {
continue;
}
for (String mediaType : mediaCodecInfo.getSupportedTypes()) {
- if (mediaType.equalsIgnoreCase("video/av01")
- || mediaType.equalsIgnoreCase("video/hevc")) {
+ if (mediaType.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)
+ || mediaType.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
MediaCodecInfo.CodecCapabilities codecCapabilities =
mediaCodecInfo.getCapabilitiesForType(mediaType);
for (int i = 0; i < codecCapabilities.colorFormats.length; ++i) {
if (codecCapabilities.colorFormats[i]
== MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010) {
- if (mediaType.equalsIgnoreCase("video/av01")) {
+ if (mediaType.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)) {
sIsP010SupportedForAV1 = true;
} else {
sIsP010SupportedForHEVC = true;
diff --git a/graphics/java/android/graphics/MeshSpecification.java b/graphics/java/android/graphics/MeshSpecification.java
index 70311fdb2d1f..b1aae7f37c31 100644
--- a/graphics/java/android/graphics/MeshSpecification.java
+++ b/graphics/java/android/graphics/MeshSpecification.java
@@ -28,11 +28,40 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Class responsible for holding specifications for {@link Mesh} creations. This class
- * generates a {@link MeshSpecification} via the Make method, where multiple parameters to set up
- * the mesh are supplied, including attributes, vertex stride, varyings, and
- * vertex/fragment shaders. There are also additional methods to provide an optional
- * {@link ColorSpace} as well as an alpha type.
+ * Class responsible for holding specifications for {@link Mesh} creations. This class generates a
+ * {@link MeshSpecification} via the
+ * {@link MeshSpecification#make(Attribute[], int, Varying[], String, String)} method,
+ * where multiple parameters to set up the mesh are supplied, including attributes, vertex stride,
+ * {@link Varying}, and vertex/fragment shaders. There are also additional methods to provide an
+ * optional {@link ColorSpace} as well as an alpha type.
+ *
+ * For example a vertex shader that leverages a {@link Varying} may look like the following:
+ *
+ * <pre>
+ * Varyings main(const Attributes attributes) {
+ * Varyings varyings;
+ * varyings.position = attributes.position;
+ * return varyings;
+ * }
+ * </pre>
+ *
+ * The corresponding fragment shader that may consume the varying look like the following:
+ *
+ * <pre>
+ * float2 main(const Varyings varyings, out float4 color) {
+ * color = vec4(1.0, 0.0, 0.0, 1.0);
+ * return varyings.position;
+ * }
+ * </pre>
+ *
+ * The color returned from this fragment shader is blended with the other parameters that are
+ * configured on the Paint object (ex. {@link Paint#setBlendMode(BlendMode)} used to draw the mesh.
+ *
+ * The position returned in the fragment shader can be consumed by any following fragment shaders in
+ * the shader chain.
+ *
+ * See https://developer.android.com/develop/ui/views/graphics/agsl for more information
+ * regarding Android Graphics Shader Language.
*
* Note that there are several limitations on various mesh specifications:
* 1. The max amount of attributes allowed is 8.
@@ -118,7 +147,11 @@ public class MeshSpecification {
public static final int TYPE_UBYTE4 = 4;
/**
- * Data class to represent a single attribute in a shader.
+ * Data class to represent a single attribute in a shader. An attribute is a variable that
+ * accompanies a vertex, this can be a color or texture coordinates.
+ *
+ * See https://developer.android.com/develop/ui/views/graphics/agsl for more information
+ * regarding Android Graphics Shader Language.
*
* Note that offset is the offset in number of bytes. For example, if we had two attributes
*
@@ -128,6 +161,10 @@ public class MeshSpecification {
* </pre>
*
* att1 would have an offset of 0, while att2 would have an offset of 12 bytes.
+ *
+ * This is consumed as part of
+ * {@link MeshSpecification#make(Attribute[], int, Varying[], String, String, ColorSpace, int)}
+ * to create a {@link MeshSpecification} instance.
*/
public static class Attribute {
@Type
@@ -175,7 +212,15 @@ public class MeshSpecification {
}
/**
- * Data class to represent a single varying variable.
+ * Data class to represent a single varying variable. A Varying variable can be altered by the
+ * vertex shader defined on the mesh but not by the fragment shader defined by AGSL.
+ *
+ * See https://developer.android.com/develop/ui/views/graphics/agsl for more information
+ * regarding Android Graphics Shader Language.
+ *
+ * This is consumed as part of
+ * {@link MeshSpecification#make(Attribute[], int, Varying[], String, String, ColorSpace, int)}
+ * to create a {@link MeshSpecification} instance.
*/
public static class Varying {
@Type
@@ -220,7 +265,7 @@ public class MeshSpecification {
/**
* Creates a {@link MeshSpecification} object for use within {@link Mesh}. This uses a default
- * color space of {@link ColorSpace.Named#SRGB} and {@link AlphaType} of
+ * color space of {@link ColorSpace.Named#SRGB} and alphaType of
* {@link #ALPHA_TYPE_PREMULTIPLIED}.
*
* @param attributes list of attributes represented by {@link Attribute}. Can hold a max of
@@ -233,7 +278,11 @@ public class MeshSpecification {
* the 6 varyings allowed.
* @param vertexShader vertex shader to be supplied to the mesh. Ensure that the position
* varying is set within the shader to get proper results.
+ * See {@link MeshSpecification} for an example vertex shader
+ * implementation
* @param fragmentShader fragment shader to be supplied to the mesh.
+ * See {@link MeshSpecification} for an example fragment shader
+ * implementation
* @return {@link MeshSpecification} object for use when creating {@link Mesh}
*/
@NonNull
@@ -253,7 +302,7 @@ public class MeshSpecification {
}
/**
- * Creates a {@link MeshSpecification} object. This uses a default {@link AlphaType} of
+ * Creates a {@link MeshSpecification} object. This uses a default alphaType of
* {@link #ALPHA_TYPE_PREMULTIPLIED}.
*
* @param attributes list of attributes represented by {@link Attribute}. Can hold a max of
@@ -266,7 +315,11 @@ public class MeshSpecification {
* the 6 varyings allowed.
* @param vertexShader vertex shader to be supplied to the mesh. Ensure that the position
* varying is set within the shader to get proper results.
+ * See {@link MeshSpecification} for an example vertex shader
+ * implementation
* @param fragmentShader fragment shader to be supplied to the mesh.
+ * See {@link MeshSpecification} for an example fragment shader
+ * implementation
* @param colorSpace {@link ColorSpace} to tell what color space to work in.
* @return {@link MeshSpecification} object for use when creating {@link Mesh}
*/
@@ -301,7 +354,11 @@ public class MeshSpecification {
* the 6 varyings allowed.
* @param vertexShader vertex shader to be supplied to the mesh. Ensure that the position
* varying is set within the shader to get proper results.
+ * See {@link MeshSpecification} for an example vertex shader
+ * implementation
* @param fragmentShader fragment shader to be supplied to the mesh.
+ * See {@link MeshSpecification} for an example fragment shader
+ * implementation
* @param colorSpace {@link ColorSpace} to tell what color space to work in.
* @param alphaType Describes how to interpret the alpha component for a pixel. Must be
* one of
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 6a79bc1f46c2..54978bd4496d 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -125,34 +125,6 @@ prebuilt_etc {
// End ProtoLog
-gensrcs {
- name: "wm-shell-protos",
-
- tools: [
- "aprotoc",
- "protoc-gen-javastream",
- "soong_zip",
- ],
-
- tool_files: [
- ":libprotobuf-internal-protos",
- ],
-
- cmd: "mkdir -p $(genDir)/$(in) " +
- "&& $(location aprotoc) " +
- " --plugin=$(location protoc-gen-javastream) " +
- " --javastream_out=$(genDir)/$(in) " +
- " -Iexternal/protobuf/src " +
- " -I . " +
- " $(in) " +
- "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
-
- srcs: [
- "proto/**/*.proto",
- ],
- output_extension: "srcjar",
-}
-
java_library {
name: "WindowManager-Shell-proto",
@@ -170,7 +142,6 @@ android_library {
// TODO(b/168581922) protologtool do not support kotlin(*.kt)
":wm_shell-sources-kt",
":wm_shell-aidls",
- ":wm-shell-protos",
],
resource_dirs: [
"res",
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
deleted file mode 100644
index 876ee02a8adf..000000000000
--- a/libs/WindowManager/Shell/res/color/taskbar_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-<!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
-</selector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color-night/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
index 01df006f1bd2..01df006f1bd2 100644
--- a/libs/WindowManager/Shell/res/color-night/taskbar_background.xml
+++ b/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
diff --git a/libs/WindowManager/Shell/res/values-night/colors.xml b/libs/WindowManager/Shell/res/values-night/colors.xml
index 5c6bb57a7f1c..83c4d93982f4 100644
--- a/libs/WindowManager/Shell/res/values-night/colors.xml
+++ b/libs/WindowManager/Shell/res/values-night/colors.xml
@@ -15,7 +15,6 @@
-->
<resources>
- <color name="docked_divider_handle">#ffffff</color>
<!-- Bubbles -->
<color name="bubbles_icon_tint">@color/GM2_grey_200</color>
<!-- Splash screen-->
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index c487e4afd678..54a8f33fd679 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -17,8 +17,8 @@
*/
-->
<resources>
- <color name="docked_divider_handle">#000000</color>
- <color name="split_divider_background">@color/taskbar_background</color>
+ <color name="docked_divider_handle">#ffffff</color>
+ <color name="split_divider_background">@color/taskbar_background_dark</color>
<drawable name="forced_resizable_background">#59000000</drawable>
<color name="minimize_dock_shadow_start">#60000000</color>
<color name="minimize_dock_shadow_end">#00000000</color>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
index 544d75739547..410ae78dba1b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
@@ -181,6 +181,17 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer {
}
/**
+ * Returns the list of display ids that are tracked by a {@link DisplayAreaInfo}
+ */
+ public int[] getDisplayIds() {
+ int[] displayIds = new int[mDisplayAreasInfo.size()];
+ for (int i = 0; i < mDisplayAreasInfo.size(); i++) {
+ displayIds[i] = mDisplayAreasInfo.keyAt(i);
+ }
+ return displayIds;
+ }
+
+ /**
* Returns the {@link DisplayAreaInfo} of the {@link DisplayAreaInfo#displayId}.
*/
@Nullable
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index b6fd0bbafc71..9aac694e41bf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -421,7 +421,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
/**
* Removes listener.
*/
- public void removeLocusIdListener(FocusListener listener) {
+ public void removeFocusListener(FocusListener listener) {
synchronized (mLock) {
mFocusListeners.remove(listener);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
index c767376d4f29..18615f7e353a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
@@ -19,6 +19,8 @@ package com.android.wm.shell.activityembedding;
import static android.graphics.Matrix.MTRANS_X;
import static android.graphics.Matrix.MTRANS_Y;
+import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationRunner.shouldUseSnapshotAnimationForClosingChange;
+
import android.annotation.CallSuper;
import android.graphics.Point;
import android.graphics.Rect;
@@ -97,10 +99,17 @@ class ActivityEmbeddingAnimationAdapter {
final Rect startBounds = change.getStartAbsBounds();
final Rect endBounds = change.getEndAbsBounds();
mContentBounds.set(startBounds);
- mContentRelOffset.set(change.getEndRelOffset());
- mContentRelOffset.offset(
- startBounds.left - endBounds.left,
- startBounds.top - endBounds.top);
+ // Put the transition to the top left for snapshot animation.
+ if (shouldUseSnapshotAnimationForClosingChange(mChange)) {
+ // TODO(b/275034335): Fix an issue that black hole when closing the right container
+ // in bounds change transition.
+ mContentRelOffset.set(0, 0);
+ } else {
+ mContentRelOffset.set(change.getEndRelOffset());
+ mContentRelOffset.offset(
+ startBounds.left - endBounds.left,
+ startBounds.top - endBounds.top);
+ }
} else {
mContentBounds.set(change.getEndAbsBounds());
mContentRelOffset.set(change.getEndRelOffset());
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 1df6ecda78c3..ab7c7d8ae6c8 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
@@ -21,6 +21,7 @@ import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
+import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationSpec.createShowSnapshotForClosingAnimation;
import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
import static com.android.wm.shell.transition.TransitionAnimationHelper.edgeExtendWindow;
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
@@ -42,6 +43,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationAdapter.SnapshotAdapter;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.util.TransitionUtil;
@@ -185,23 +187,23 @@ class ActivityEmbeddingAnimationRunner {
return createChangeAnimationAdapters(info, startTransaction);
}
if (TransitionUtil.isClosingType(info.getType())) {
- return createCloseAnimationAdapters(info);
+ return createCloseAnimationAdapters(info, startTransaction);
}
- return createOpenAnimationAdapters(info);
+ return createOpenAnimationAdapters(info, startTransaction);
}
@NonNull
private List<ActivityEmbeddingAnimationAdapter> createOpenAnimationAdapters(
- @NonNull TransitionInfo info) {
+ @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
return createOpenCloseAnimationAdapters(info, true /* isOpening */,
- mAnimationSpec::loadOpenAnimation);
+ mAnimationSpec::loadOpenAnimation, startTransaction);
}
@NonNull
private List<ActivityEmbeddingAnimationAdapter> createCloseAnimationAdapters(
- @NonNull TransitionInfo info) {
+ @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
return createOpenCloseAnimationAdapters(info, false /* isOpening */,
- mAnimationSpec::loadCloseAnimation);
+ mAnimationSpec::loadCloseAnimation, startTransaction);
}
/**
@@ -211,7 +213,8 @@ class ActivityEmbeddingAnimationRunner {
@NonNull
private List<ActivityEmbeddingAnimationAdapter> createOpenCloseAnimationAdapters(
@NonNull TransitionInfo info, boolean isOpening,
- @NonNull AnimationProvider animationProvider) {
+ @NonNull AnimationProvider animationProvider,
+ @NonNull SurfaceControl.Transaction startTransaction) {
// We need to know if the change window is only a partial of the whole animation screen.
// If so, we will need to adjust it to make the whole animation screen looks like one.
final List<TransitionInfo.Change> openingChanges = new ArrayList<>();
@@ -224,6 +227,8 @@ class ActivityEmbeddingAnimationRunner {
openingWholeScreenBounds.union(change.getEndAbsBounds());
} else {
closingChanges.add(change);
+ // Also union with the start bounds because the closing transition may be shrunk.
+ closingWholeScreenBounds.union(change.getStartAbsBounds());
closingWholeScreenBounds.union(change.getEndAbsBounds());
}
}
@@ -241,6 +246,17 @@ class ActivityEmbeddingAnimationRunner {
adapters.add(adapter);
}
for (TransitionInfo.Change change : closingChanges) {
+ if (shouldUseSnapshotAnimationForClosingChange(change)) {
+ SurfaceControl screenshot = getOrCreateScreenshot(change, change, startTransaction);
+ if (screenshot != null) {
+ final SnapshotAdapter snapshotAdapter = new SnapshotAdapter(
+ createShowSnapshotForClosingAnimation(), change, screenshot);
+ if (!isOpening) {
+ snapshotAdapter.overrideLayer(offsetLayer++);
+ }
+ adapters.add(snapshotAdapter);
+ }
+ }
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
info, change, animationProvider, closingWholeScreenBounds);
if (!isOpening) {
@@ -251,6 +267,22 @@ class ActivityEmbeddingAnimationRunner {
return adapters;
}
+ /**
+ * Returns whether we should use snapshot animation for the closing change.
+ * It's usually because the end bounds of the closing change are shrunk, which leaves a black
+ * area in the transition.
+ */
+ static boolean shouldUseSnapshotAnimationForClosingChange(
+ @NonNull TransitionInfo.Change closingChange) {
+ // Only check closing type because we only take screenshot for closing bounds-changing
+ // changes.
+ if (!TransitionUtil.isClosingType(closingChange.getMode())) {
+ return false;
+ }
+ // Don't need to take screenshot if there's no bounds change.
+ return !closingChange.getStartAbsBounds().equals(closingChange.getEndAbsBounds());
+ }
+
/** Sets the first frame to the {@code startTransaction} to avoid any flicker on start. */
private void prepareForFirstFrame(@NonNull SurfaceControl.Transaction startTransaction,
@NonNull List<ActivityEmbeddingAnimationAdapter> adapters) {
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 cb8342a10a6a..19eff0e43169 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
@@ -77,6 +77,15 @@ class ActivityEmbeddingAnimationSpec {
return new AlphaAnimation(alpha, alpha);
}
+ /**
+ * Animation that intended to show snapshot for closing animation because the closing end bounds
+ * are changed.
+ */
+ @NonNull
+ static Animation createShowSnapshotForClosingAnimation() {
+ return new AlphaAnimation(1f, 1f);
+ }
+
/** Animation for window that is opening in a change transition. */
@NonNull
Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo.Change change,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index b9ff5f0e820a..e7ec7aa164e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -2884,6 +2884,7 @@ public class BubbleStackView extends FrameLayout
/** Hide or show the manage menu for the currently expanded bubble. */
@VisibleForTesting
public void showManageMenu(boolean show) {
+ if ((mManageMenu.getVisibility() == VISIBLE) == show) return;
mShowingManage = show;
// This should not happen, since the manage menu is only visible when there's an expanded
@@ -3319,7 +3320,9 @@ public class BubbleStackView extends FrameLayout
* @return the normalized x-axis position of the bubble stack rounded to 4 decimal places.
*/
public float getNormalizedXPosition() {
- return new BigDecimal(getStackPosition().x / mPositioner.getAvailableRect().width())
+ int width = mPositioner.getAvailableRect().width();
+ float stackPosition = width > 0 ? getStackPosition().x / width : 0;
+ return new BigDecimal(stackPosition)
.setScale(4, RoundingMode.CEILING.HALF_UP)
.floatValue();
}
@@ -3328,7 +3331,9 @@ public class BubbleStackView extends FrameLayout
* @return the normalized y-axis position of the bubble stack rounded to 4 decimal places.
*/
public float getNormalizedYPosition() {
- return new BigDecimal(getStackPosition().y / mPositioner.getAvailableRect().height())
+ int height = mPositioner.getAvailableRect().height();
+ float stackPosition = height > 0 ? getStackPosition().y / height : 0;
+ return new BigDecimal(stackPosition)
.setScale(4, RoundingMode.CEILING.HALF_UP)
.floatValue();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
index b8204d013105..0bcafe513b4f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
@@ -59,4 +59,17 @@ public class SplitScreenConstants {
/** Flag applied to a transition change to identify it as a divider bar for animation. */
public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
+
+ public static final String splitPositionToString(@SplitPosition int pos) {
+ switch (pos) {
+ case SPLIT_POSITION_UNDEFINED:
+ return "SPLIT_POSITION_UNDEFINED";
+ case SPLIT_POSITION_TOP_OR_LEFT:
+ return "SPLIT_POSITION_TOP_OR_LEFT";
+ case SPLIT_POSITION_BOTTOM_OR_RIGHT:
+ return "SPLIT_POSITION_BOTTOM_OR_RIGHT";
+ default:
+ return "UNKNOWN";
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 80e920fefe5f..28368ef37061 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -189,12 +189,13 @@ public abstract class WMShellBaseModule {
static Optional<DragAndDropController> provideDragAndDropController(Context context,
ShellInit shellInit,
ShellController shellController,
+ ShellCommandHandler shellCommandHandler,
DisplayController displayController,
UiEventLogger uiEventLogger,
IconProvider iconProvider,
@ShellMainThread ShellExecutor mainExecutor) {
return Optional.ofNullable(DragAndDropController.create(context, shellInit, shellController,
- displayController, uiEventLogger, iconProvider, mainExecutor));
+ shellCommandHandler, displayController, uiEventLogger, iconProvider, mainExecutor));
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
index d1760ed75547..76ca68bbfa75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
@@ -49,6 +49,12 @@ public class DesktopModeStatus {
"persist.wm.debug.desktop_veiled_resizing", true);
/**
+ * Flag to indicate is moving task to another display is enabled.
+ */
+ public static final boolean IS_DISPLAY_CHANGE_ENABLED = SystemProperties.getBoolean(
+ "persist.wm.debug.desktop_change_display", false);
+
+ /**
* Return {@code true} if desktop mode support is enabled
*/
public static boolean isProto1Enabled() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index fb0a91f17802..0f0d572f8eae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -162,7 +162,7 @@ public class DesktopModeVisualIndicator {
/**
* Release the indicator and its components when it is no longer needed.
*/
- public void releaseVisualIndicator() {
+ public void releaseVisualIndicator(SurfaceControl.Transaction t) {
if (mViewHost == null) return;
if (mViewHost != null) {
mViewHost.release();
@@ -170,13 +170,8 @@ public class DesktopModeVisualIndicator {
}
if (mLeash != null) {
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.remove(mLeash);
mLeash = null;
- mSyncQueue.runInSync(transaction -> {
- transaction.merge(t);
- t.close();
- });
}
}
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 c814fe575e81..ee94f30cfa69 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
@@ -78,6 +78,11 @@ class DesktopTasksController(
private val desktopMode: DesktopModeImpl
private var visualIndicator: DesktopModeVisualIndicator? = null
+ private val mOnAnimationFinishedCallback = Consumer<SurfaceControl.Transaction> {
+ t: SurfaceControl.Transaction ->
+ visualIndicator?.releaseVisualIndicator(t)
+ visualIndicator = null
+ }
init {
desktopMode = DesktopModeImpl()
@@ -154,14 +159,14 @@ class DesktopTasksController(
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
enterDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_ENTER_FREEFORM, wct)
+ Transitions.TRANSIT_ENTER_FREEFORM, wct, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
}
}
/** Brings apps to front and sets freeform task bounds */
- fun moveToDesktopWithAnimation(
+ private fun moveToDesktopWithAnimation(
taskInfo: RunningTaskInfo,
freeformBounds: Rect
) {
@@ -172,9 +177,10 @@ class DesktopTasksController(
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
enterDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct)
+ Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
+ releaseVisualIndicator()
}
}
@@ -205,21 +211,24 @@ class DesktopTasksController(
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, startPosition)
+ enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, startPosition,
+ mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
+ releaseVisualIndicator()
}
}
- fun moveToFullscreenWithAnimation(task: ActivityManager.RunningTaskInfo) {
+ private fun moveToFullscreenWithAnimation(task: ActivityManager.RunningTaskInfo) {
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
exitDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct)
+ Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
+ releaseVisualIndicator()
}
}
@@ -235,6 +244,69 @@ class DesktopTasksController(
}
/**
+ * Move task to the next display.
+ *
+ * Queries all current known display ids and sorts them in ascending order. Then iterates
+ * through the list and looks for the display id that is larger than the display id for
+ * the passed in task. If a display with a higher id is not found, iterates through the list and
+ * finds the first display id that is not the display id for the passed in task.
+ *
+ * If a display matching the above criteria is found, re-parents the task to that display.
+ * No-op if no such display is found.
+ */
+ fun moveToNextDisplay(taskId: Int) {
+ val task = shellTaskOrganizer.getRunningTaskInfo(taskId)
+ if (task == null) {
+ ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d not found", taskId)
+ return
+ }
+ ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d taskDisplayId=%d",
+ taskId, task.displayId)
+
+ val displayIds = rootTaskDisplayAreaOrganizer.displayIds.sorted()
+ // Get the first display id that is higher than current task display id
+ var newDisplayId = displayIds.firstOrNull { displayId -> displayId > task.displayId }
+ if (newDisplayId == null) {
+ // No display with a higher id, get the first display id that is not the task display id
+ newDisplayId = displayIds.firstOrNull { displayId -> displayId < task.displayId }
+ }
+ if (newDisplayId == null) {
+ ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: next display not found")
+ return
+ }
+ moveToDisplay(task, newDisplayId)
+ }
+
+ /**
+ * Move [task] to display with [displayId].
+ *
+ * No-op if task is already on that display per [RunningTaskInfo.displayId].
+ */
+ private fun moveToDisplay(task: RunningTaskInfo, displayId: Int) {
+ ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToDisplay: taskId=%d displayId=%d",
+ task.taskId, displayId)
+
+ if (task.displayId == displayId) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "moveToDisplay: task already on display")
+ return
+ }
+
+ val displayAreaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
+ if (displayAreaInfo == null) {
+ ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToDisplay: display not found")
+ return
+ }
+
+ val wct = WindowContainerTransaction()
+ wct.reparent(task.token, displayAreaInfo.token, true /* onTop */)
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
+ } else {
+ shellTaskOrganizer.applyTransaction(wct)
+ }
+ }
+
+ /**
* Get windowing move for a given `taskId`
*
* @return [WindowingMode] for the task or [WINDOWING_MODE_UNDEFINED] if task is not found
@@ -267,6 +339,16 @@ class DesktopTasksController(
?.let { homeTask -> wct.reorder(homeTask.getToken(), true /* onTop */) }
}
+ private fun releaseVisualIndicator() {
+ val t = SurfaceControl.Transaction()
+ visualIndicator?.releaseVisualIndicator(t)
+ visualIndicator = null
+ syncQueue.runInSync { transaction ->
+ transaction.merge(t)
+ t.close()
+ }
+ }
+
override fun getContext(): Context {
return context
}
@@ -408,8 +490,7 @@ class DesktopTasksController(
rootTaskDisplayAreaOrganizer)
visualIndicator?.createFullscreenIndicatorWithAnimatedBounds()
} else if (y > statusBarHeight && visualIndicator != null) {
- visualIndicator?.releaseVisualIndicator()
- visualIndicator = null
+ releaseVisualIndicator()
}
}
}
@@ -426,8 +507,6 @@ class DesktopTasksController(
) {
val statusBarHeight = getStatusBarHeight(taskInfo)
if (y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
- visualIndicator?.releaseVisualIndicator()
- visualIndicator = null
moveToFullscreenWithAnimation(taskInfo)
}
}
@@ -445,6 +524,11 @@ class DesktopTasksController(
taskSurface: SurfaceControl,
y: Float
) {
+ // If the motion event is above the status bar, return since we do not need to show the
+ // visual indicator at this point.
+ if (y < getStatusBarHeight(taskInfo)) {
+ return
+ }
if (visualIndicator == null) {
visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo,
displayController, context, taskSurface, shellTaskOrganizer,
@@ -472,11 +556,8 @@ class DesktopTasksController(
freeformBounds: Rect
) {
moveToDesktopWithAnimation(taskInfo, freeformBounds)
- visualIndicator?.releaseVisualIndicator()
- visualIndicator = null
}
-
private fun getStatusBarHeight(taskInfo: RunningTaskInfo): Int {
return displayController.getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0
}
@@ -503,7 +584,6 @@ class DesktopTasksController(
desktopModeTaskRepository.removeTaskCorners(taskId)
}
-
/**
* Adds a listener to find out about changes in the visibility of freeform tasks.
*
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 94675788c514..d55fdddf4fea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -39,6 +39,7 @@ import com.android.wm.shell.transition.Transitions;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Supplier;
/**
@@ -58,6 +59,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
private Point mStartPosition;
+ private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
public EnterDesktopTaskTransitionHandler(
Transitions transitions) {
@@ -75,9 +77,12 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
* Starts Transition of a given type
* @param type Transition type
* @param wct WindowContainerTransaction for transition
+ * @param onAnimationEndCallback to be called after animation
*/
public void startTransition(@WindowManager.TransitionType int type,
- @NonNull WindowContainerTransaction wct) {
+ @NonNull WindowContainerTransaction wct,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ mOnAnimationFinishedCallback = onAnimationEndCallback;
final IBinder token = mTransitions.startTransition(type, wct, this);
mPendingTransitionTokens.add(token);
}
@@ -86,11 +91,14 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
* Starts Transition of type TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
* @param wct WindowContainerTransaction for transition
* @param startPosition Position of task when transition is triggered
+ * @param onAnimationEndCallback to be called after animation
*/
public void startCancelMoveToDesktopMode(@NonNull WindowContainerTransaction wct,
- Point startPosition) {
+ Point startPosition,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
mStartPosition = startPosition;
- startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct);
+ startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct,
+ mOnAnimationFinishedCallback);
}
@Override
@@ -111,7 +119,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
if (change.getMode() == WindowManager.TRANSIT_CHANGE) {
transitionHandled |= startChangeTransition(
- transition, info.getType(), change, startT, finishCallback);
+ transition, info.getType(), change, startT, finishT, finishCallback);
}
}
@@ -125,6 +133,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
@WindowManager.TransitionType int type,
@NonNull TransitionInfo.Change change,
@NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
if (!mPendingTransitionTokens.contains(transition)) {
return false;
@@ -178,6 +187,9 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
mTransitions.getMainExecutor().execute(
() -> finishCallback.onTransitionFinished(null, null));
}
@@ -204,7 +216,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
animator.setDuration(FREEFORM_ANIMATION_DURATION);
final SurfaceControl.Transaction t = mTransactionSupplier.get();
animator.addUpdateListener(animation -> {
- final float scale = animation.getAnimatedFraction();
+ final float scale = (float) animation.getAnimatedValue();
t.setPosition(sc, mStartPosition.x * (1 - scale), mStartPosition.y * (1 - scale))
.setScale(sc, scale, scale)
.show(sc)
@@ -213,6 +225,9 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
mTransitions.getMainExecutor().execute(
() -> finishCallback.onTransitionFinished(null, null));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index fa3eee257a52..160a83d7ed36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -42,6 +42,7 @@ import com.android.wm.shell.transition.Transitions;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -54,7 +55,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
private final Context mContext;
private final Transitions mTransitions;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
-
+ private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
private Supplier<SurfaceControl.Transaction> mTransactionSupplier;
public ExitDesktopTaskTransitionHandler(
@@ -76,9 +77,12 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
* Starts Transition of a given type
* @param type Transition type
* @param wct WindowContainerTransaction for transition
+ * @param onAnimationEndCallback to be called after animation
*/
public void startTransition(@WindowManager.TransitionType int type,
- @NonNull WindowContainerTransaction wct) {
+ @NonNull WindowContainerTransaction wct,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ mOnAnimationFinishedCallback = onAnimationEndCallback;
final IBinder token = mTransitions.startTransition(type, wct, this);
mPendingTransitionTokens.add(token);
}
@@ -101,7 +105,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
if (change.getMode() == WindowManager.TRANSIT_CHANGE) {
transitionHandled |= startChangeTransition(
- transition, info.getType(), change, startT, finishCallback);
+ transition, info.getType(), change, startT, finishT, finishCallback);
}
}
@@ -116,6 +120,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
@WindowManager.TransitionType int type,
@NonNull TransitionInfo.Change change,
@NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
if (!mPendingTransitionTokens.contains(transition)) {
return false;
@@ -156,6 +161,9 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
mTransitions.getMainExecutor().execute(
() -> finishCallback.onTransitionFinished(null, null));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 091de3a86461..be2489da3628 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -35,10 +35,14 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
+
import android.content.ClipDescription;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.HardwareRenderer;
import android.graphics.PixelFormat;
import android.util.Slog;
import android.util.SparseArray;
@@ -50,6 +54,8 @@ import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
+import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.InstanceId;
@@ -58,25 +64,31 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
+import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalMainThread;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
+import java.io.PrintWriter;
import java.util.ArrayList;
/**
* Handles the global drag and drop handling for the Shell.
*/
-public class DragAndDropController implements DisplayController.OnDisplaysChangedListener,
+public class DragAndDropController implements RemoteCallable<DragAndDropController>,
+ DisplayController.OnDisplaysChangedListener,
View.OnDragListener, ComponentCallbacks2 {
private static final String TAG = DragAndDropController.class.getSimpleName();
private final Context mContext;
private final ShellController mShellController;
+ private final ShellCommandHandler mShellCommandHandler;
private final DisplayController mDisplayController;
private final DragAndDropEventLogger mLogger;
private final IconProvider mIconProvider;
@@ -100,6 +112,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
public static DragAndDropController create(Context context,
ShellInit shellInit,
ShellController shellController,
+ ShellCommandHandler shellCommandHandler,
DisplayController displayController,
UiEventLogger uiEventLogger,
IconProvider iconProvider,
@@ -107,19 +120,21 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
if (!context.getResources().getBoolean(R.bool.config_enableShellDragDrop)) {
return null;
}
- return new DragAndDropController(context, shellInit, shellController, displayController,
- uiEventLogger, iconProvider, mainExecutor);
+ return new DragAndDropController(context, shellInit, shellController, shellCommandHandler,
+ displayController, uiEventLogger, iconProvider, mainExecutor);
}
DragAndDropController(Context context,
ShellInit shellInit,
ShellController shellController,
+ ShellCommandHandler shellCommandHandler,
DisplayController displayController,
UiEventLogger uiEventLogger,
IconProvider iconProvider,
ShellExecutor mainExecutor) {
mContext = context;
mShellController = shellController;
+ mShellCommandHandler = shellCommandHandler;
mDisplayController = displayController;
mLogger = new DragAndDropEventLogger(uiEventLogger);
mIconProvider = iconProvider;
@@ -137,6 +152,23 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
mMainExecutor.executeDelayed(() -> {
mDisplayController.addDisplayWindowListener(this);
}, 0);
+ mShellController.addExternalInterface(KEY_EXTRA_SHELL_DRAG_AND_DROP,
+ this::createExternalInterface, this);
+ mShellCommandHandler.addDumpCallback(this::dump, this);
+ }
+
+ private ExternalInterfaceBinder createExternalInterface() {
+ return new IDragAndDropImpl(this);
+ }
+
+ @Override
+ public Context getContext() {
+ return mContext;
+ }
+
+ @Override
+ public ShellExecutor getRemoteCallExecutor() {
+ return mMainExecutor;
}
/**
@@ -156,7 +188,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
mListeners.remove(listener);
}
- private void notifyListeners() {
+ private void notifyDragStarted() {
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onDragStarted();
}
@@ -273,7 +305,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
event.getClipData(), loggerSessionId);
setDropTargetWindowVisibility(pd, View.VISIBLE);
- notifyListeners();
+ notifyDragStarted();
break;
case ACTION_DRAG_ENTERED:
pd.dragLayout.show();
@@ -327,13 +359,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
}
private void setDropTargetWindowVisibility(PerDisplay pd, int visibility) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
- "Set drop target window visibility: displayId=%d visibility=%d",
- pd.displayId, visibility);
- pd.rootView.setVisibility(visibility);
- if (visibility == View.VISIBLE) {
- pd.rootView.requestApplyInsets();
- }
+ pd.setWindowVisibility(visibility);
}
private String getMimeTypes(ClipDescription description) {
@@ -347,6 +373,18 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
return mimeTypes;
}
+ /**
+ * Returns if any displays are currently ready to handle a drag/drop.
+ */
+ private boolean isReadyToHandleDrag() {
+ for (int i = 0; i < mDisplayDropTargets.size(); i++) {
+ if (mDisplayDropTargets.valueAt(i).mHasDrawn) {
+ return true;
+ }
+ }
+ return false;
+ }
+
// Note: Component callbacks are always called on the main thread of the process
@ExternalMainThread
@Override
@@ -372,12 +410,53 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
// Do nothing
}
- private static class PerDisplay {
+ /**
+ * Dumps information about this controller.
+ */
+ public void dump(@NonNull PrintWriter pw, String prefix) {
+ pw.println(prefix + TAG);
+ pw.println(prefix + " listeners=" + mListeners.size());
+ }
+
+ /**
+ * The interface for calls from outside the host process.
+ */
+ @BinderThread
+ private static class IDragAndDropImpl extends IDragAndDrop.Stub
+ implements ExternalInterfaceBinder {
+ private DragAndDropController mController;
+
+ public IDragAndDropImpl(DragAndDropController controller) {
+ mController = controller;
+ }
+
+ /**
+ * Invalidates this instance, preventing future calls from updating the controller.
+ */
+ @Override
+ public void invalidate() {
+ mController = null;
+ }
+
+ @Override
+ public boolean isReadyToHandleDrag() {
+ boolean[] result = new boolean[1];
+ executeRemoteCallWithTaskPermission(mController, "isReadyToHandleDrag",
+ controller -> result[0] = controller.isReadyToHandleDrag(),
+ true /* blocking */
+ );
+ return result[0];
+ }
+ }
+
+ private static class PerDisplay implements HardwareRenderer.FrameDrawingCallback {
final int displayId;
final Context context;
final WindowManager wm;
final FrameLayout rootView;
final DragLayout dragLayout;
+ // Tracks whether the window has fully drawn since it was last made visible
+ boolean mHasDrawn;
boolean isHandlingDrag;
// A count of the number of active drags in progress to ensure that we only hide the window
@@ -391,5 +470,25 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
rootView = rv;
dragLayout = dl;
}
+
+ private void setWindowVisibility(int visibility) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
+ "Set drop target window visibility: displayId=%d visibility=%d",
+ displayId, visibility);
+ rootView.setVisibility(visibility);
+ if (visibility == View.VISIBLE) {
+ rootView.requestApplyInsets();
+ if (!mHasDrawn && rootView.getViewRootImpl() != null) {
+ rootView.getViewRootImpl().registerRtFrameCallback(this);
+ }
+ } else {
+ mHasDrawn = false;
+ }
+ }
+
+ @Override
+ public void onFrameDraw(long frame) {
+ mHasDrawn = true;
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index 28f59b53b5b6..724a130ef52d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -104,7 +104,7 @@ public class DropZoneView extends FrameLayout {
setContainerMargin(0, 0, 0, 0); // make sure it's populated
mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
- mMarginColor = getResources().getColor(R.color.taskbar_background);
+ mMarginColor = getResources().getColor(R.color.taskbar_background_dark);
int c = getResources().getColor(android.R.color.system_accent1_500);
mHighlightColor = Color.argb(HIGHLIGHT_ALPHA, Color.red(c), Color.green(c), Color.blue(c));
mSplashScreenColor = Color.argb(SPLASHSCREEN_ALPHA, 0, 0, 0);
@@ -125,7 +125,7 @@ public class DropZoneView extends FrameLayout {
public void onThemeChange() {
mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(getContext());
- mMarginColor = getResources().getColor(R.color.taskbar_background);
+ mMarginColor = getResources().getColor(R.color.taskbar_background_dark);
mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
if (mMarginPercent > 0) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/IDragAndDrop.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/IDragAndDrop.aidl
new file mode 100644
index 000000000000..aeb0c63fa4c5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/IDragAndDrop.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop;
+
+/**
+ * Interface that is exposed to remote callers to manipulate drag and drop.
+ */
+interface IDragAndDrop {
+ /**
+ * Returns whether the shell drop target is showing and will handle a drag/drop.
+ */
+ boolean isReadyToHandleDrag() = 1;
+}
+// Last id = 1 \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index e1a56a1a5a7a..6b6a7bc42046 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -153,6 +153,8 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
@Override
public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {
+ mWindowDecorViewModel.onTransitionMerged(merged, playing);
+
final List<ActivityManager.RunningTaskInfo> infoOfMerged =
mTransitionToTaskInfo.get(merged);
if (infoOfMerged == null) {
@@ -169,8 +171,6 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
} else {
mTransitionToTaskInfo.put(playing, infoOfMerged);
}
-
- mWindowDecorViewModel.onTransitionMerged(merged, playing);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index d3e7f9ca4227..6cedcf534f3b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -27,6 +27,7 @@ import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.wm.shell.pip.PipAnimationController.FRACTION_START;
@@ -524,12 +525,18 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
}
- final Rect destinationBounds = getExitDestinationBounds();
+ final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+ final Rect destinationBounds = new Rect(displayBounds);
final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_LEAVE_PIP;
+ // For exiting to fullscreen, the windowing mode of task will be changed to fullscreen
+ // until the animation is finished. Otherwise if the activity is resumed and focused at the
+ // begin of aniamtion, the app may do something too early to distub the animation.
+ final boolean toFullscreen = destinationBounds.equals(displayBounds);
- if (Transitions.ENABLE_SHELL_TRANSITIONS && direction == TRANSITION_DIRECTION_LEAVE_PIP) {
+ if (Transitions.SHELL_TRANSITIONS_ROTATION || (Transitions.ENABLE_SHELL_TRANSITIONS
+ && !toFullscreen)) {
// When exit to fullscreen with Shell transition enabled, we update the Task windowing
// mode directly so that it can also trigger display rotation and visibility update in
// the same transition if there will be any.
@@ -605,7 +612,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
removePip();
}
- private void applyWindowingModeChangeOnExit(WindowContainerTransaction wct, int direction) {
+ void applyWindowingModeChangeOnExit(WindowContainerTransaction wct, int direction) {
// Reset the final windowing mode.
wct.setWindowingMode(mToken, getOutPipWindowingMode());
// Simply reset the activity mode set prior to the animation running.
@@ -1771,14 +1778,26 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
* @return {@code true} if destinationBounds is altered for split screen
*/
private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut, boolean enterSplit) {
- if (!enterSplit || !mSplitScreenOptional.isPresent()) {
+ if (mSplitScreenOptional.isEmpty()) {
+ return false;
+ }
+ final SplitScreenController split = mSplitScreenOptional.get();
+ final int position = mTaskInfo.lastParentTaskIdBeforePip > 0
+ ? split.getSplitPosition(mTaskInfo.lastParentTaskIdBeforePip)
+ : SPLIT_POSITION_UNDEFINED;
+ if (position == SPLIT_POSITION_UNDEFINED && !enterSplit) {
return false;
}
final Rect topLeft = new Rect();
final Rect bottomRight = new Rect();
- mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
- destinationBoundsOut.set(isPipToTopLeft() ? topLeft : bottomRight);
- return true;
+ split.getStageBounds(topLeft, bottomRight);
+ if (enterSplit) {
+ destinationBoundsOut.set(isPipToTopLeft() ? topLeft : bottomRight);
+ return true;
+ }
+ // Moving to an existing split task.
+ destinationBoundsOut.set(position == SPLIT_POSITION_TOP_OR_LEFT ? topLeft : bottomRight);
+ return false;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 99cb6f782d01..98db707d1105 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -508,8 +508,16 @@ public class PipTransition extends PipTransitionController {
currentBounds.offset(-offset.x, -offset.y);
startTransaction.setPosition(pipLeash, currentBounds.left, currentBounds.top);
+ final WindowContainerToken pipTaskToken = pipChange.getContainer();
+ final boolean toFullscreen = pipChange.getEndAbsBounds().equals(
+ mPipBoundsState.getDisplayBounds());
mFinishCallback = (wct, wctCB) -> {
mPipOrganizer.onExitPipFinished(taskInfo);
+ if (!Transitions.SHELL_TRANSITIONS_ROTATION && toFullscreen) {
+ wct = wct != null ? wct : new WindowContainerTransaction();
+ wct.setBounds(pipTaskToken, null);
+ mPipOrganizer.applyWindowingModeChangeOnExit(wct, TRANSITION_DIRECTION_LEAVE_PIP);
+ }
finishCallback.onTransitionFinished(wct, wctCB);
};
mFinishTransaction = finishTransaction;
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 bffc51c6b22f..3e568e9cb996 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
@@ -48,6 +48,7 @@ import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -97,7 +98,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
mMixers.remove(mixer);
}
- void startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options,
+ @VisibleForTesting
+ public IBinder startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options,
IApplicationThread appThread, IRecentsAnimationRunner listener) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"RecentsTransitionHandler.startRecentsTransition");
@@ -121,12 +123,13 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
if (mixer != null) {
mixer.setRecentsTransition(transition);
}
- if (transition == null) {
+ if (transition != null) {
+ controller.setTransition(transition);
+ mControllers.add(controller);
+ } else {
controller.cancel("startRecentsTransition");
- return;
}
- controller.setTransition(transition);
- mControllers.add(controller);
+ return transition;
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 0ef26fcff284..e5ae10c097a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -39,6 +39,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIV
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.common.split.SplitScreenConstants.splitPositionToString;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
@@ -378,40 +379,18 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitPosition int stagePosition,
WindowContainerTransaction wct) {
- StageTaskListener targetStage;
- int sideStagePosition;
- if (isSplitScreenVisible()) {
- // If the split screen is foreground, retrieves target stage based on position.
- targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
- sideStagePosition = mSideStagePosition;
+ prepareEnterSplitScreen(wct, task, stagePosition);
+ if (ENABLE_SHELL_TRANSITIONS) {
+ mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct,
+ null, this, null /* consumedCallback */, null /* finishedCallback */,
+ isSplitScreenVisible()
+ ? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN);
} else {
- targetStage = mSideStage;
- sideStagePosition = stagePosition;
- }
-
- if (!isSplitActive()) {
- mSplitLayout.init();
- prepareEnterSplitScreen(wct, task, stagePosition);
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
- setDividerVisibility(true, t);
});
- } else {
- setSideStagePosition(sideStagePosition, wct);
- targetStage.addTask(task, wct);
- targetStage.evictAllChildren(wct);
- if (!isSplitScreenVisible()) {
- final StageTaskListener anotherStage = targetStage == mMainStage
- ? mSideStage : mMainStage;
- anotherStage.reparentTopTask(wct);
- anotherStage.evictAllChildren(wct);
- wct.reorder(mRootTaskInfo.token, true);
- }
- setRootForceTranslucent(false, wct);
- mSyncQueue.queue(wct);
}
-
// Due to drag already pip task entering split by this method so need to reset flag here.
mIsDropEntering = false;
return true;
@@ -1509,9 +1488,51 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
*/
void prepareEnterSplitScreen(WindowContainerTransaction wct,
@Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
- if (mMainStage.isActive()) return;
-
onSplitScreenEnter();
+ if (isSplitActive()) {
+ prepareBringSplit(wct, taskInfo, startPosition);
+ } else {
+ prepareActiveSplit(wct, taskInfo, startPosition);
+ }
+ }
+
+ private void prepareBringSplit(WindowContainerTransaction wct,
+ @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
+ StageTaskListener targetStage;
+ if (isSplitScreenVisible()) {
+ // If the split screen is foreground, retrieves target stage based on position.
+ targetStage = startPosition == mSideStagePosition ? mSideStage : mMainStage;
+ } else {
+ targetStage = mSideStage;
+ }
+
+ if (taskInfo != null) {
+ wct.startTask(taskInfo.taskId,
+ resolveStartStage(STAGE_TYPE_UNDEFINED, startPosition, null, wct));
+ targetStage.evictAllChildren(wct);
+ }
+ // If running background, we need to reparent current top visible task to another stage
+ // and evict all tasks current under its.
+ if (!isSplitScreenVisible()) {
+ // Recreate so we need to reset position rather than keep position of background split.
+ mSplitLayout.resetDividerPosition();
+ updateWindowBounds(mSplitLayout, wct);
+ final StageTaskListener anotherStage = targetStage == mMainStage
+ ? mSideStage : mMainStage;
+ anotherStage.evictAllChildren(wct);
+ anotherStage.reparentTopTask(wct);
+ wct.reorder(mRootTaskInfo.token, true);
+ setRootForceTranslucent(false, wct);
+ }
+ }
+
+ private void prepareActiveSplit(WindowContainerTransaction wct,
+ @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
+ if (!ENABLE_SHELL_TRANSITIONS) {
+ // Legacy transition we need to create divider here, shell transition case we will
+ // create it on #finishEnterSplitScreen
+ mSplitLayout.init();
+ }
if (taskInfo != null) {
setSideStagePosition(startPosition, wct);
mSideStage.addTask(taskInfo, wct);
@@ -2383,7 +2404,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (taskInfo == null || !taskInfo.hasParentTask()) continue;
+ if (taskInfo == null) continue;
+ if (taskInfo.token.equals(mRootTaskInfo.token)) {
+ if (isOpeningType(change.getMode())) {
+ // Split is opened by someone so set it as visible.
+ setSplitsVisible(true);
+ } else if (isClosingType(change.getMode())) {
+ // Split is closed by someone so set it as invisible.
+ setSplitsVisible(false);
+ }
+ continue;
+ }
final StageTaskListener stage = getStageOfTask(taskInfo);
if (stage == null) continue;
if (isOpeningType(change.getMode())) {
@@ -2823,12 +2854,18 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final String childPrefix = innerPrefix + " ";
pw.println(prefix + TAG + " mDisplayId=" + mDisplayId);
pw.println(innerPrefix + "mDividerVisible=" + mDividerVisible);
+ pw.println(innerPrefix + "isSplitActive=" + isSplitActive());
+ pw.println(innerPrefix + "isSplitVisible=" + isSplitScreenVisible());
pw.println(innerPrefix + "MainStage");
- pw.println(childPrefix + "stagePosition=" + getMainStagePosition());
+ pw.println(childPrefix + "stagePosition=" + splitPositionToString(getMainStagePosition()));
pw.println(childPrefix + "isActive=" + mMainStage.isActive());
+ mMainStage.dump(pw, childPrefix);
+ pw.println(innerPrefix + "MainStageListener");
mMainStageListener.dump(pw, childPrefix);
pw.println(innerPrefix + "SideStage");
- pw.println(childPrefix + "stagePosition=" + getSideStagePosition());
+ pw.println(childPrefix + "stagePosition=" + splitPositionToString(getSideStagePosition()));
+ mSideStage.dump(pw, childPrefix);
+ pw.println(innerPrefix + "SideStageListener");
mSideStageListener.dump(pw, childPrefix);
if (mMainStage.isActive()) {
pw.println(innerPrefix + "SplitLayout");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index a841b7f96d3c..18b09b090794 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -421,6 +421,13 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
final String childPrefix = innerPrefix + " ";
- pw.println(prefix + this);
+ if (mChildrenTaskInfo.size() > 0) {
+ pw.println(prefix + "Children list:");
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+ final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
+ pw.println(childPrefix + "Task#" + i + " taskID=" + taskInfo.taskId
+ + " baseActivity=" + taskInfo.baseActivity);
+ }
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
index 8a4d4c21194a..ae722208782e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
@@ -477,15 +477,15 @@ class SplashscreenWindowCreator extends AbsSplashWindowCreator {
}
@Override
- public void removeIfPossible(StartingWindowRemovalInfo info, boolean immediately) {
+ public boolean removeIfPossible(StartingWindowRemovalInfo info, boolean immediately) {
if (mRootView == null) {
- return;
+ return true;
}
if (mSplashView == null) {
// shouldn't happen, the app window may be drawn earlier than starting window?
Slog.e(TAG, "Found empty splash screen, remove!");
removeWindowInner(mRootView, false);
- return;
+ return true;
}
clearSystemBarColor();
if (immediately
@@ -503,6 +503,7 @@ class SplashscreenWindowCreator extends AbsSplashWindowCreator {
removeWindowInner(mRootView, true);
}
}
+ return true;
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index ff06db370d1a..7cbf263f7cb1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -18,6 +18,8 @@ package com.android.wm.shell.startingsurface;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.StartingWindowRemovalInfo.DEFER_MODE_NORMAL;
+import static android.window.StartingWindowRemovalInfo.DEFER_MODE_ROTATION;
import android.annotation.CallSuper;
import android.app.TaskInfo;
@@ -216,7 +218,17 @@ public class StartingSurfaceDrawer {
}
abstract static class StartingWindowRecord {
protected int mBGColor;
- abstract void removeIfPossible(StartingWindowRemovalInfo info, boolean immediately);
+
+ /**
+ * Remove the starting window with the given {@link StartingWindowRemovalInfo} if possible.
+ * @param info The removal info sent from the task organizer controller in the WM core.
+ * @param immediately {@code true} means removing the starting window immediately,
+ * {@code false} otherwise.
+ * @return {@code true} means {@link StartingWindowRecordManager} can safely remove the
+ * record itself. {@code false} means {@link StartingWindowRecordManager} requires
+ * to manage the record reference and remove it later.
+ */
+ abstract boolean removeIfPossible(StartingWindowRemovalInfo info, boolean immediately);
int getBGColor() {
return mBGColor;
}
@@ -231,6 +243,15 @@ public class StartingSurfaceDrawer {
* {@link StartingSurfaceDrawer#onImeDrawnOnTask(int)}.
*/
private static final long MAX_DELAY_REMOVAL_TIME_IME_VISIBLE = 600;
+
+ /**
+ * The max delay time in milliseconds for removing the task snapshot window with IME
+ * visible after the fixed rotation finished.
+ * Ideally the delay time will be shorter when receiving
+ * {@link StartingSurfaceDrawer#onImeDrawnOnTask(int)}.
+ */
+ private static final long MAX_DELAY_REMOVAL_TIME_FIXED_ROTATION = 3000;
+
private final Runnable mScheduledRunnable = this::removeImmediately;
@WindowConfiguration.ActivityType protected final int mActivityType;
@@ -242,24 +263,34 @@ public class StartingSurfaceDrawer {
}
@Override
- public final void removeIfPossible(StartingWindowRemovalInfo info, boolean immediately) {
+ public final boolean removeIfPossible(StartingWindowRemovalInfo info, boolean immediately) {
if (immediately) {
removeImmediately();
} else {
- scheduleRemove(info.deferRemoveForIme);
+ scheduleRemove(info.deferRemoveForImeMode);
+ return false;
}
+ return true;
}
- void scheduleRemove(boolean deferRemoveForIme) {
+ void scheduleRemove(@StartingWindowRemovalInfo.DeferMode int deferRemoveForImeMode) {
// Show the latest content as soon as possible for unlocking to home.
if (mActivityType == ACTIVITY_TYPE_HOME) {
removeImmediately();
return;
}
mRemoveExecutor.removeCallbacks(mScheduledRunnable);
- final long delayRemovalTime = hasImeSurface() && deferRemoveForIme
- ? MAX_DELAY_REMOVAL_TIME_IME_VISIBLE
- : DELAY_REMOVAL_TIME_GENERAL;
+ final long delayRemovalTime;
+ switch (deferRemoveForImeMode) {
+ case DEFER_MODE_ROTATION:
+ delayRemovalTime = MAX_DELAY_REMOVAL_TIME_FIXED_ROTATION;
+ break;
+ case DEFER_MODE_NORMAL:
+ delayRemovalTime = MAX_DELAY_REMOVAL_TIME_IME_VISIBLE;
+ break;
+ default:
+ delayRemovalTime = DELAY_REMOVAL_TIME_GENERAL;
+ }
mRemoveExecutor.executeDelayed(mScheduledRunnable, delayRemovalTime);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
"Defer removing snapshot surface in %d", delayRemovalTime);
@@ -297,8 +328,10 @@ public class StartingSurfaceDrawer {
final int taskId = removeInfo.taskId;
final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
if (record != null) {
- record.removeIfPossible(removeInfo, immediately);
- mStartingWindowRecords.remove(taskId);
+ final boolean canRemoveRecord = record.removeIfPossible(removeInfo, immediately);
+ if (canRemoveRecord) {
+ mStartingWindowRecords.remove(taskId);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSplashWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSplashWindowCreator.java
index 12a0d4054b4d..98a803128587 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSplashWindowCreator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSplashWindowCreator.java
@@ -124,7 +124,7 @@ class WindowlessSplashWindowCreator extends AbsSplashWindowCreator {
}
@Override
- public void removeIfPossible(StartingWindowRemovalInfo info, boolean immediately) {
+ public boolean removeIfPossible(StartingWindowRemovalInfo info, boolean immediately) {
if (!immediately) {
mSplashscreenContentDrawer.applyExitAnimation(mSplashView,
info.windowAnimationLeash, info.mainFrame,
@@ -132,6 +132,7 @@ class WindowlessSplashWindowCreator extends AbsSplashWindowCreator {
} else {
release();
}
+ return true;
}
void release() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
index bfa63909cd47..5f54f58557d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
@@ -42,4 +42,6 @@ public class ShellSharedConstants {
public static final String KEY_EXTRA_SHELL_FLOATING_TASKS = "extra_shell_floating_tasks";
// See IDesktopMode.aidl
public static final String KEY_EXTRA_SHELL_DESKTOP_MODE = "extra_shell_desktop_mode";
+ // See IDragAndDrop.aidl
+ public static final String KEY_EXTRA_SHELL_DRAG_AND_DROP = "extra_shell_drag_and_drop";
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index c7e534a2bcf5..2faed3a4b93d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -202,6 +202,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
}
void setTaskViewVisible(TaskViewTaskController taskView, boolean visible) {
+ if (mTaskViews.get(taskView) == null) return;
if (mTaskViews.get(taskView).mVisible == visible) return;
if (taskView.getTaskInfo() == null) {
// Nothing to update, task is not yet available
@@ -220,17 +221,19 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
void updateBoundsState(TaskViewTaskController taskView, Rect boundsOnScreen) {
TaskViewRequestedState state = mTaskViews.get(taskView);
+ if (state == null) return;
state.mBounds.set(boundsOnScreen);
}
void updateVisibilityState(TaskViewTaskController taskView, boolean visible) {
TaskViewRequestedState state = mTaskViews.get(taskView);
+ if (state == null) return;
state.mVisible = visible;
}
void setTaskBounds(TaskViewTaskController taskView, Rect boundsOnScreen) {
TaskViewRequestedState state = mTaskViews.get(taskView);
- if (Objects.equals(boundsOnScreen, state.mBounds)) {
+ if (state == null || Objects.equals(boundsOnScreen, state.mBounds)) {
return;
}
state.mBounds.set(boundsOnScreen);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 7c729a46b679..49429327572e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -73,7 +73,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
/** Pip was entered while handling an intent with its own remoteTransition. */
static final int TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE = 3;
- /** Recents transition while split-screen active. */
+ /** Recents transition while split-screen foreground. */
static final int TYPE_RECENTS_DURING_SPLIT = 4;
/** The default animation for this mixed transition. */
@@ -152,7 +152,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@NonNull TransitionRequestInfo request) {
if (mPipHandler.requestHasPipEnter(request) && mSplitHandler.isSplitScreenVisible()) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a PiP-enter request while "
- + "Split-Screen is active, so treat it as Mixed.");
+ + "Split-Screen is foreground, so treat it as Mixed.");
if (request.getRemoteTransition() != null) {
throw new IllegalStateException("Unexpected remote transition in"
+ "pip-enter-from-split request");
@@ -183,13 +183,13 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
mixed.mLeftoversHandler = handler.first;
mActiveTransitions.add(mixed);
return handler.second;
- } else if (mSplitHandler.isSplitActive()
+ } else if (mSplitHandler.isSplitScreenVisible()
&& isOpeningType(request.getType())
&& request.getTriggerTask() != null
&& request.getTriggerTask().getWindowingMode() == WINDOWING_MODE_FULLSCREEN
&& request.getTriggerTask().getActivityType() == ACTIVITY_TYPE_HOME) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a going-home request while "
- + "Split-Screen is active, so treat it as Mixed.");
+ + "Split-Screen is foreground, so treat it as Mixed.");
Pair<Transitions.TransitionHandler, WindowContainerTransaction> handler =
mPlayer.dispatchRequest(transition, request, this);
if (handler == null) {
@@ -211,7 +211,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@Override
public Transitions.TransitionHandler handleRecentsRequest(WindowContainerTransaction outWCT) {
- if (mRecentsHandler != null && mSplitHandler.isSplitActive()) {
+ if (mRecentsHandler != null && mSplitHandler.isSplitScreenVisible()) {
return this;
}
return null;
@@ -219,9 +219,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@Override
public void setRecentsTransition(IBinder transition) {
- if (mSplitHandler.isSplitActive()) {
+ if (mSplitHandler.isSplitScreenVisible()) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
- + "Split-Screen is active, so treat it as Mixed.");
+ + "Split-Screen is foreground, so treat it as Mixed.");
final MixedTransition mixed = new MixedTransition(
MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition);
mixed.mLeftoversHandler = mRecentsHandler;
@@ -351,7 +351,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animating a mixed transition for "
- + "entering PIP while Split-Screen is active.");
+ + "entering PIP while Split-Screen is foreground.");
TransitionInfo.Change pipChange = null;
TransitionInfo.Change wallpaper = null;
final TransitionInfo everythingElse = subCopy(info, TRANSIT_TO_BACK, true /* changes */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 6e9ecdaf55e7..1ee52ae00645 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -21,6 +21,7 @@ import static android.app.ActivityOptions.ANIM_CUSTOM;
import static android.app.ActivityOptions.ANIM_NONE;
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.ActivityOptions.ANIM_SCALE_UP;
+import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -625,6 +626,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
} else if ((changeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0 && isOpeningType) {
// This received a transferred starting window, so don't animate
return null;
+ } else if (overrideType == ANIM_SCENE_TRANSITION) {
+ // If there's a scene-transition, then jump-cut.
+ return null;
} else {
a = loadAttributeAnimation(info, change, wallpaperTransit, mTransitionAnimation);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index d25318df6b6a..9ce22094d56b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -144,6 +144,7 @@ class ScreenRotationAnimation {
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.setSourceCrop(new Rect(0, 0, mStartWidth, mStartHeight))
+ .setHintForSeamlessTransition(true)
.build();
ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
ScreenCapture.captureLayers(args);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
index ba364f8a6e59..0cede902f034 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
@@ -18,25 +18,29 @@ package com.android.wm.shell.transition;
import static android.os.Build.IS_USER;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_H;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_L;
+import static com.android.wm.shell.nano.WmShellTransitionTraceProto.MAGIC_NUMBER_H;
+import static com.android.wm.shell.nano.WmShellTransitionTraceProto.MAGIC_NUMBER_L;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.SystemClock;
import android.os.Trace;
import android.util.Log;
-import android.util.proto.ProtoOutputStream;
import com.android.internal.util.TraceBuffer;
+import com.android.wm.shell.nano.HandlerMapping;
import com.android.wm.shell.sysui.ShellCommandHandler;
+import com.google.protobuf.nano.MessageNano;
+
import java.io.File;
import java.io.IOException;
+import java.io.OutputStream;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
+import java.util.Queue;
/**
* Helper class to collect and dump transition traces.
@@ -54,8 +58,35 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
private final Object mEnabledLock = new Object();
private boolean mActiveTracingEnabled = false;
- private final TraceBuffer mTraceBuffer = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY,
- (proto) -> handleOnEntryRemovedFromTrace(proto));
+ private final TraceBuffer.ProtoProvider mProtoProvider =
+ new TraceBuffer.ProtoProvider<MessageNano,
+ com.android.wm.shell.nano.WmShellTransitionTraceProto,
+ com.android.wm.shell.nano.Transition>() {
+ @Override
+ public int getItemSize(MessageNano proto) {
+ return proto.getCachedSize();
+ }
+
+ @Override
+ public byte[] getBytes(MessageNano proto) {
+ return MessageNano.toByteArray(proto);
+ }
+
+ @Override
+ public void write(
+ com.android.wm.shell.nano.WmShellTransitionTraceProto encapsulatingProto,
+ Queue<com.android.wm.shell.nano.Transition> buffer, OutputStream os)
+ throws IOException {
+ encapsulatingProto.transitions = buffer.toArray(
+ new com.android.wm.shell.nano.Transition[0]);
+ os.write(getBytes(encapsulatingProto));
+ }
+ };
+ private final TraceBuffer<MessageNano,
+ com.android.wm.shell.nano.WmShellTransitionTraceProto,
+ com.android.wm.shell.nano.Transition> mTraceBuffer
+ = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY, mProtoProvider,
+ (proto) -> handleOnEntryRemovedFromTrace(proto));
private final Map<Object, Runnable> mRemovedFromTraceCallbacks = new HashMap<>();
private final Map<Transitions.TransitionHandler, Integer> mHandlerIds = new HashMap<>();
@@ -78,26 +109,20 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
mHandlerIds.put(handler, handlerId);
}
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
-
- outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
- outputStream.write(com.android.wm.shell.Transition.DISPATCH_TIME_NS,
- SystemClock.elapsedRealtimeNanos());
- outputStream.write(com.android.wm.shell.Transition.HANDLER, handlerId);
-
- outputStream.end(protoToken);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = transitionId;
+ proto.dispatchTimeNs = SystemClock.elapsedRealtimeNanos();
+ proto.handler = handlerId;
final int useCountAfterAdd = mHandlerUseCountInTrace.getOrDefault(handler, 0) + 1;
mHandlerUseCountInTrace.put(handler, useCountAfterAdd);
- mRemovedFromTraceCallbacks.put(outputStream, () -> {
+ mRemovedFromTraceCallbacks.put(proto, () -> {
final int useCountAfterRemove = mHandlerUseCountInTrace.get(handler) - 1;
mHandlerUseCountInTrace.put(handler, useCountAfterRemove);
});
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -107,18 +132,12 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
* @param playingTransitionId The id of the transition we was to merge the transition into.
*/
public void logMergeRequested(int mergeRequestedTransitionId, int playingTransitionId) {
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
-
- outputStream.write(com.android.wm.shell.Transition.ID, mergeRequestedTransitionId);
- outputStream.write(com.android.wm.shell.Transition.MERGE_REQUEST_TIME_NS,
- SystemClock.elapsedRealtimeNanos());
- outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = mergeRequestedTransitionId;
+ proto.mergeRequestTimeNs = SystemClock.elapsedRealtimeNanos();
+ proto.mergedInto = playingTransitionId;
- outputStream.end(protoToken);
-
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -128,18 +147,12 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
* @param playingTransitionId The id of the transition the transition was merged into.
*/
public void logMerged(int mergedTransitionId, int playingTransitionId) {
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
-
- outputStream.write(com.android.wm.shell.Transition.ID, mergedTransitionId);
- outputStream.write(
- com.android.wm.shell.Transition.MERGE_TIME_NS, SystemClock.elapsedRealtimeNanos());
- outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = mergedTransitionId;
+ proto.mergeTimeNs = SystemClock.elapsedRealtimeNanos();
+ proto.mergedInto = playingTransitionId;
- outputStream.end(protoToken);
-
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -148,17 +161,11 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
* @param transitionId The id of the transition that was aborted.
*/
public void logAborted(int transitionId) {
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
-
- outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
- outputStream.write(
- com.android.wm.shell.Transition.ABORT_TIME_NS, SystemClock.elapsedRealtimeNanos());
-
- outputStream.end(protoToken);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = transitionId;
+ proto.abortTimeNs = SystemClock.elapsedRealtimeNanos();
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -230,8 +237,9 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
private void writeTraceToFileLocked(@Nullable PrintWriter pw, File file) {
Trace.beginSection("TransitionTracer#writeTraceToFileLocked");
try {
- ProtoOutputStream proto = new ProtoOutputStream();
- proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ com.android.wm.shell.nano.WmShellTransitionTraceProto proto =
+ new com.android.wm.shell.nano.WmShellTransitionTraceProto();
+ proto.magicNumber = MAGIC_NUMBER_VALUE;
writeHandlerMappingToProto(proto);
int pid = android.os.Process.myPid();
LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath()
@@ -243,19 +251,21 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
Trace.endSection();
}
- private void writeHandlerMappingToProto(ProtoOutputStream outputStream) {
+ private void writeHandlerMappingToProto(
+ com.android.wm.shell.nano.WmShellTransitionTraceProto proto) {
+ ArrayList<com.android.wm.shell.nano.HandlerMapping> handlerMappings = new ArrayList<>();
for (Transitions.TransitionHandler handler : mHandlerUseCountInTrace.keySet()) {
final int count = mHandlerUseCountInTrace.get(handler);
if (count > 0) {
- final long protoToken = outputStream.start(
- com.android.wm.shell.WmShellTransitionTraceProto.HANDLER_MAPPINGS);
- outputStream.write(com.android.wm.shell.HandlerMapping.ID,
- mHandlerIds.get(handler));
- outputStream.write(com.android.wm.shell.HandlerMapping.NAME,
- handler.getClass().getName());
- outputStream.end(protoToken);
+ com.android.wm.shell.nano.HandlerMapping mapping =
+ new com.android.wm.shell.nano.HandlerMapping();
+ mapping.id = mHandlerIds.get(handler);
+ mapping.name = handler.getClass().getName();
+ handlerMappings.add(mapping);
}
}
+ proto.handlerMappings = handlerMappings.toArray(
+ new com.android.wm.shell.nano.HandlerMapping[0]);
}
private void handleOnEntryRemovedFromTrace(Object proto) {
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 f79f1f7a27b1..a73ab776486b 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
@@ -533,8 +533,12 @@ public class Transitions implements RemoteCallable<Transitions>,
final int layer;
// Put all the OPEN/SHOW on top
if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
- // Wallpaper is always at the bottom.
- layer = -zSplitLine;
+ // Wallpaper is always at the bottom, opening wallpaper on top of closing one.
+ if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
+ layer = -zSplitLine + numChanges - i;
+ } else {
+ layer = -zSplitLine - i;
+ }
} else if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
if (isOpening) {
// put on top
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 4ef3350d06a4..dffbedd197cf 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
@@ -111,12 +111,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
private ValueAnimator mDragToDesktopValueAnimator;
private final Rect mDragToDesktopAnimationStartBounds = new Rect();
private boolean mDragToDesktopAnimationStarted;
- private float mCaptionDragStartX;
-
- // These values keep track of any transitions to freeform to stop relayout from running on
- // changing task so that shellTransitions has a chance to animate the transition
- private int mPauseRelayoutForTask = -1;
- private IBinder mTransitionPausingRelayout;
public DesktopModeWindowDecorViewModel(
Context context,
@@ -195,22 +189,25 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change) {
if (change.getMode() == WindowManager.TRANSIT_CHANGE
- && info.getType() == Transitions.TRANSIT_ENTER_DESKTOP_MODE) {
- mTransitionPausingRelayout = transition;
+ && (info.getType() == Transitions.TRANSIT_ENTER_DESKTOP_MODE)) {
+ mWindowDecorByTaskId.get(change.getTaskInfo().taskId)
+ .addTransitionPausingRelayout(transition);
}
}
@Override
public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {
- if (merged.equals(mTransitionPausingRelayout)) {
- mTransitionPausingRelayout = playing;
+ for (int i = 0; i < mWindowDecorByTaskId.size(); i++) {
+ final DesktopModeWindowDecoration decor = mWindowDecorByTaskId.valueAt(i);
+ decor.mergeTransitionPausingRelayout(merged, playing);
}
}
@Override
public void onTransitionFinished(@NonNull IBinder transition) {
- if (transition.equals(mTransitionPausingRelayout)) {
- mPauseRelayoutForTask = -1;
+ for (int i = 0; i < mWindowDecorByTaskId.size(); i++) {
+ final DesktopModeWindowDecoration decor = mWindowDecorByTaskId.valueAt(i);
+ decor.removeTransitionPausingRelayout(transition);
}
}
@@ -225,12 +222,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
incrementEventReceiverTasks(taskInfo.displayId);
}
- // TaskListener callbacks and shell transitions aren't synchronized, so starting a shell
- // transition can trigger an onTaskInfoChanged call that updates the task's SurfaceControl
- // and interferes with the transition animation that is playing at the same time.
- if (taskInfo.taskId != mPauseRelayoutForTask) {
- decoration.relayout(taskInfo);
- }
+ decoration.relayout(taskInfo);
}
@Override
@@ -333,6 +325,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
decoration.closeHandleMenu();
} else if (id == R.id.collapse_menu_button) {
decoration.closeHandleMenu();
+ } else if (id == R.id.select_button) {
+ if (DesktopModeStatus.IS_DISPLAY_CHANGE_ENABLED) {
+ // TODO(b/278084491): dev option to enable display switching
+ // remove when select is implemented
+ mDesktopTasksController.ifPresent(c -> c.moveToNextDisplay(mTaskId));
+ decoration.closeHandleMenu();
+ }
}
}
@@ -525,7 +524,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
DesktopModeWindowDecoration relevantDecor) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
- mCaptionDragStartX = ev.getX();
// Begin drag through status bar if applicable.
if (relevantDecor != null) {
mDragToDesktopAnimationStartBounds.set(
@@ -555,8 +553,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
relevantDecor.mTaskInfo.displayId);
if (ev.getY() > 2 * statusBarHeight) {
if (DesktopModeStatus.isProto2Enabled()) {
- mPauseRelayoutForTask = relevantDecor.mTaskInfo.taskId;
- centerAndMoveToDesktopWithAnimation(relevantDecor, ev);
+ animateToDesktop(relevantDecor, ev);
} else if (DesktopModeStatus.isProto1Enabled()) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
}
@@ -581,8 +578,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
if (mTransitionDragActive) {
mDesktopTasksController.ifPresent(
- c -> c.onDragPositioningMoveThroughStatusBar(relevantDecor.mTaskInfo,
- relevantDecor.mTaskSurface, ev.getY()));
+ c -> c.onDragPositioningMoveThroughStatusBar(
+ relevantDecor.mTaskInfo,
+ relevantDecor.mTaskSurface, ev.getY()));
final int statusBarHeight = getStatusBarHeight(
relevantDecor.mTaskInfo.displayId);
if (ev.getY() > statusBarHeight) {
@@ -632,6 +630,15 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
/**
+ * Blocks relayout until transition is finished and transitions to Desktop
+ */
+ private void animateToDesktop(DesktopModeWindowDecoration relevantDecor,
+ MotionEvent ev) {
+ relevantDecor.incrementRelayoutBlock();
+ centerAndMoveToDesktopWithAnimation(relevantDecor, ev);
+ }
+
+ /**
* Animates a window to the center, grows to freeform size, and transitions to Desktop Mode.
* @param relevantDecor the window decor of the task to be animated
* @param ev the motion event that triggers the animation
@@ -658,10 +665,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mDesktopTasksController.ifPresent(
- c -> c.onDragPositioningEndThroughStatusBar(
- relevantDecor.mTaskInfo,
- calculateFreeformBounds(FINAL_FREEFORM_SCALE)));
+ mDesktopTasksController.ifPresent(c ->
+ c.onDragPositioningEndThroughStatusBar(relevantDecor.mTaskInfo,
+ calculateFreeformBounds(FINAL_FREEFORM_SCALE)));
}
});
animator.start();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index b1c3791ad15a..95ed42a222b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -30,6 +30,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.IBinder;
import android.util.Log;
import android.view.Choreographer;
import android.view.MotionEvent;
@@ -49,6 +50,9 @@ import com.android.wm.shell.windowdecor.viewholder.DesktopModeAppControlsWindowD
import com.android.wm.shell.windowdecor.viewholder.DesktopModeFocusedWindowDecorationViewHolder;
import com.android.wm.shell.windowdecor.viewholder.DesktopModeWindowDecorationViewHolder;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
* {@link DesktopModeWindowDecorViewModel}.
@@ -83,6 +87,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
private TaskCornersListener mCornersListener;
+ private final Set<IBinder> mTransitionsPausingRelayout = new HashSet<>();
+ private int mRelayoutBlock;
+
DesktopModeWindowDecoration(
Context context,
DisplayController displayController,
@@ -134,6 +141,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
@Override
void relayout(ActivityManager.RunningTaskInfo taskInfo) {
+ // TaskListener callbacks and shell transitions aren't synchronized, so starting a shell
+ // transition can trigger an onTaskInfoChanged call that updates the task's SurfaceControl
+ // and interferes with the transition animation that is playing at the same time.
+ if (mRelayoutBlock > 0) {
+ return;
+ }
+
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
// Use |applyStartTransactionOnDraw| so that the transaction (that applies task crop) is
// synced with the buffer transaction (that draws the View). Both will be shown on screen
@@ -455,6 +469,40 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
return cornersRegion;
}
+ /**
+ * If transition exists in mTransitionsPausingRelayout, remove the transition and decrement
+ * mRelayoutBlock
+ */
+ void removeTransitionPausingRelayout(IBinder transition) {
+ if (mTransitionsPausingRelayout.remove(transition)) {
+ mRelayoutBlock--;
+ }
+ }
+
+ /**
+ * Add transition to mTransitionsPausingRelayout
+ */
+ void addTransitionPausingRelayout(IBinder transition) {
+ mTransitionsPausingRelayout.add(transition);
+ }
+
+ /**
+ * If two transitions merge and the merged transition is in mTransitionsPausingRelayout,
+ * remove the merged transition from the set and add the transition it was merged into.
+ */
+ public void mergeTransitionPausingRelayout(IBinder merged, IBinder playing) {
+ if (mTransitionsPausingRelayout.remove(merged)) {
+ mTransitionsPausingRelayout.add(playing);
+ }
+ }
+
+ /**
+ * Increase mRelayoutBlock, stopping relayout if mRelayoutBlock is now greater than 0.
+ */
+ public void incrementRelayoutBlock() {
+ mRelayoutBlock++;
+ }
+
static class Factory {
DesktopModeWindowDecoration create(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
index ed3cca078084..ac4a597c15d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
@@ -187,6 +187,8 @@ class HandleMenu {
final View moreActionsPillView = mMoreActionsPill.mWindowViewHost.getView();
final Button closeBtn = moreActionsPillView.findViewById(R.id.close_button);
closeBtn.setOnClickListener(mOnClickListener);
+ final Button selectBtn = moreActionsPillView.findViewById(R.id.select_button);
+ selectBtn.setOnClickListener(mOnClickListener);
}
/**
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index b6d92814ad43..b5937ae80f0a 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -21,6 +21,9 @@
<option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
<!-- Ensure output directory is empty at the start -->
<option name="run-command" value="rm -rf /sdcard/flicker" />
+ <!-- Increase trace size: 20mb for WM and 80mb for SF -->
+ <option name="run-command" value="cmd window tracing size 20480" />
+ <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
new file mode 100644
index 000000000000..e06e074ee98a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.app.Instrumentation
+import android.tools.device.flicker.junit.FlickerBuilderProvider
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
+
+abstract class BaseBenchmarkTest
+@JvmOverloads
+constructor(
+ protected open val flicker: FlickerTest,
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
+ protected val tapl: LauncherInstrumentation = LauncherInstrumentation()
+) {
+ /** Specification of the test transition to execute */
+ abstract val transition: FlickerBuilder.() -> Unit
+
+ /**
+ * Entry point for the test runner. It will use this method to initialize and cache flicker
+ * executions
+ */
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup { flicker.scenario.setIsTablet(tapl.isTablet) }
+ transition()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
index 86edc25b64d3..c98c5a0ad1a6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
@@ -17,24 +17,10 @@
package com.android.wm.shell.flicker
import android.app.Instrumentation
-import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerBuilderProvider
-import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
-import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsVisibleAtStartAndEnd
-import com.android.server.wm.flicker.statusBarLayerPositionAtStartAndEnd
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.taskBarLayerIsVisibleAtStartAndEnd
-import com.android.server.wm.flicker.taskBarWindowIsAlwaysVisible
-import org.junit.Assume
-import org.junit.Test
/**
* Base test class containing common assertions for [ComponentNameMatcher.NAV_BAR],
@@ -44,124 +30,7 @@ import org.junit.Test
abstract class BaseTest
@JvmOverloads
constructor(
- protected val flicker: FlickerTest,
- protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
- protected val tapl: LauncherInstrumentation = LauncherInstrumentation()
-) {
- /** Specification of the test transition to execute */
- abstract val transition: FlickerBuilder.() -> Unit
-
- /**
- * Entry point for the test runner. It will use this method to initialize and cache flicker
- * executions
- */
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- setup { flicker.scenario.setIsTablet(tapl.isTablet) }
- transition()
- }
- }
-
- /** Checks that all parts of the screen are covered during the transition */
- @Presubmit @Test open fun entireScreenCovered() = flicker.entireScreenCovered()
-
- /**
- * Checks that the [ComponentNameMatcher.NAV_BAR] layer is visible during the whole transition
- */
- @Presubmit
- @Test
- open fun navBarLayerIsVisibleAtStartAndEnd() {
- Assume.assumeFalse(flicker.scenario.isTablet)
- flicker.navBarLayerIsVisibleAtStartAndEnd()
- }
-
- /**
- * Checks the position of the [ComponentNameMatcher.NAV_BAR] at the start and end of the
- * transition
- */
- @Presubmit
- @Test
- open fun navBarLayerPositionAtStartAndEnd() {
- Assume.assumeFalse(flicker.scenario.isTablet)
- flicker.navBarLayerPositionAtStartAndEnd()
- }
-
- /**
- * Checks that the [ComponentNameMatcher.NAV_BAR] window is visible during the whole transition
- *
- * Note: Phones only
- */
- @Presubmit
- @Test
- open fun navBarWindowIsAlwaysVisible() {
- Assume.assumeFalse(flicker.scenario.isTablet)
- flicker.navBarWindowIsAlwaysVisible()
- }
-
- /**
- * Checks that the [ComponentNameMatcher.TASK_BAR] layer is visible during the whole transition
- */
- @Presubmit
- @Test
- open fun taskBarLayerIsVisibleAtStartAndEnd() {
- Assume.assumeTrue(flicker.scenario.isTablet)
- flicker.taskBarLayerIsVisibleAtStartAndEnd()
- }
-
- /**
- * Checks that the [ComponentNameMatcher.TASK_BAR] window is visible during the whole transition
- *
- * Note: Large screen only
- */
- @Presubmit
- @Test
- open fun taskBarWindowIsAlwaysVisible() {
- Assume.assumeTrue(flicker.scenario.isTablet)
- flicker.taskBarWindowIsAlwaysVisible()
- }
-
- /**
- * Checks that the [ComponentNameMatcher.STATUS_BAR] layer is visible during the whole
- * transition
- */
- @Presubmit
- @Test
- open fun statusBarLayerIsVisibleAtStartAndEnd() = flicker.statusBarLayerIsVisibleAtStartAndEnd()
-
- /**
- * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the
- * transition
- */
- @Presubmit
- @Test
- open fun statusBarLayerPositionAtStartAndEnd() = flicker.statusBarLayerPositionAtStartAndEnd()
-
- /**
- * Checks that the [ComponentNameMatcher.STATUS_BAR] window is visible during the whole
- * transition
- */
- @Presubmit
- @Test
- open fun statusBarWindowIsAlwaysVisible() = flicker.statusBarWindowIsAlwaysVisible()
-
- /**
- * Checks that all layers that are visible on the trace, are visible for at least 2 consecutive
- * entries.
- */
- @Presubmit
- @Test
- open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- flicker.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry() }
- }
-
- /**
- * Checks that all windows that are visible on the trace, are visible for at least 2 consecutive
- * entries.
- */
- @Presubmit
- @Test
- open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
- flicker.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry() }
- }
-}
+ override val flicker: FlickerTest,
+ instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
+ tapl: LauncherInstrumentation = LauncherInstrumentation()
+) : BaseBenchmarkTest(flicker, instrumentation, tapl), ICommonAssertions
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt
new file mode 100644
index 000000000000..02d9a056afbf
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.legacy.FlickerTest
+import com.android.server.wm.flicker.entireScreenCovered
+import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
+import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisibleAtStartAndEnd
+import com.android.server.wm.flicker.statusBarLayerPositionAtStartAndEnd
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.taskBarLayerIsVisibleAtStartAndEnd
+import com.android.server.wm.flicker.taskBarWindowIsAlwaysVisible
+import org.junit.Assume
+import org.junit.Test
+
+interface ICommonAssertions {
+ val flicker: FlickerTest
+
+ /** Checks that all parts of the screen are covered during the transition */
+ @Presubmit @Test fun entireScreenCovered() = flicker.entireScreenCovered()
+
+ /**
+ * Checks that the [ComponentNameMatcher.NAV_BAR] layer is visible during the whole transition
+ */
+ @Presubmit
+ @Test
+ fun navBarLayerIsVisibleAtStartAndEnd() {
+ Assume.assumeFalse(flicker.scenario.isTablet)
+ flicker.navBarLayerIsVisibleAtStartAndEnd()
+ }
+
+ /**
+ * Checks the position of the [ComponentNameMatcher.NAV_BAR] at the start and end of the
+ * transition
+ */
+ @Presubmit
+ @Test
+ fun navBarLayerPositionAtStartAndEnd() {
+ Assume.assumeFalse(flicker.scenario.isTablet)
+ flicker.navBarLayerPositionAtStartAndEnd()
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.NAV_BAR] window is visible during the whole transition
+ *
+ * Note: Phones only
+ */
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() {
+ Assume.assumeFalse(flicker.scenario.isTablet)
+ flicker.navBarWindowIsAlwaysVisible()
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.TASK_BAR] layer is visible during the whole transition
+ */
+ @Presubmit
+ @Test
+ fun taskBarLayerIsVisibleAtStartAndEnd() {
+ Assume.assumeTrue(flicker.scenario.isTablet)
+ flicker.taskBarLayerIsVisibleAtStartAndEnd()
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.TASK_BAR] window is visible during the whole transition
+ *
+ * Note: Large screen only
+ */
+ @Presubmit
+ @Test
+ fun taskBarWindowIsAlwaysVisible() {
+ Assume.assumeTrue(flicker.scenario.isTablet)
+ flicker.taskBarWindowIsAlwaysVisible()
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.STATUS_BAR] layer is visible during the whole
+ * transition
+ */
+ @Presubmit
+ @Test
+ fun statusBarLayerIsVisibleAtStartAndEnd() = flicker.statusBarLayerIsVisibleAtStartAndEnd()
+
+ /**
+ * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the
+ * transition
+ */
+ @Presubmit
+ @Test
+ fun statusBarLayerPositionAtStartAndEnd() = flicker.statusBarLayerPositionAtStartAndEnd()
+
+ /**
+ * Checks that the [ComponentNameMatcher.STATUS_BAR] window is visible during the whole
+ * transition
+ */
+ @Presubmit @Test fun statusBarWindowIsAlwaysVisible() = flicker.statusBarWindowIsAlwaysVisible()
+
+ /**
+ * Checks that all layers that are visible on the trace, are visible for at least 2 consecutive
+ * entries.
+ */
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ flicker.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry() }
+ }
+
+ /**
+ * Checks that all windows that are visible on the trace, are visible for at least 2 consecutive
+ * entries.
+ */
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ flicker.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry() }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index 11c5951faa1f..61781565270b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -18,15 +18,18 @@ package com.android.wm.shell.flicker.appcompat
import android.content.Context
import android.system.helpers.CommandsHelper
+import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.LetterboxAppHelper
import android.tools.device.flicker.legacy.FlickerTestFactory
import android.tools.device.flicker.legacy.IFlickerTestData
-import com.android.server.wm.flicker.helpers.LetterboxAppHelper
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.wm.shell.flicker.BaseTest
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
+import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.layerKeepVisible
+import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.runners.Parameterized
@@ -35,7 +38,7 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
protected val context: Context = instrumentation.context
protected val letterboxApp = LetterboxAppHelper(instrumentation)
lateinit var cmdHelper: CommandsHelper
- lateinit var letterboxStyle: HashMap<String, String>
+ private lateinit var letterboxStyle: HashMap<String, String>
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -45,12 +48,22 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
letterboxApp.launchViaIntent(wmHelper)
setEndRotation()
}
+ teardown {
+ letterboxApp.exit(wmHelper)
+ }
}
@Before
fun before() {
cmdHelper = CommandsHelper.getInstance(instrumentation)
Assume.assumeTrue(tapl.isTablet && isIgnoreOrientationRequest())
+ letterboxStyle = mapLetterboxStyle()
+ setLetterboxEducationEnabled(false)
+ }
+
+ @After
+ fun after() {
+ resetLetterboxEducationEnabled()
}
private fun mapLetterboxStyle(): HashMap<String, String> {
@@ -67,6 +80,22 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
return map
}
+ private fun getLetterboxStyle(): HashMap<String, String> {
+ if (!::letterboxStyle.isInitialized) {
+ letterboxStyle = mapLetterboxStyle()
+ }
+ return letterboxStyle
+ }
+
+ private fun resetLetterboxEducationEnabled() {
+ val enabled = getLetterboxStyle().getValue("Is education enabled")
+ cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
+ }
+
+ private fun setLetterboxEducationEnabled(enabled: Boolean) {
+ cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
+ }
+
private fun isIgnoreOrientationRequest(): Boolean {
val res = cmdHelper.executeShellCommand("wm get-ignore-orientation-request")
return res != null && res.contains("true")
@@ -89,10 +118,7 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
/** Only run on tests with config_letterboxActivityCornersRadius != 0 in devices */
private fun assumeLetterboxRoundedCornersEnabled() {
- if (!::letterboxStyle.isInitialized) {
- letterboxStyle = mapLetterboxStyle()
- }
- Assume.assumeTrue(letterboxStyle.getValue("Corner radius") != "0")
+ Assume.assumeTrue(getLetterboxStyle().getValue("Corner radius") != "0")
}
fun assertLetterboxAppVisibleAtStartAndEnd() {
@@ -100,12 +126,20 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
flicker.appWindowIsVisibleAtEnd(letterboxApp)
}
+ fun assertAppLetterboxedAtEnd() =
+ flicker.assertLayersEnd { isVisible(ComponentNameMatcher.LETTERBOX) }
+
+ fun assertAppLetterboxedAtStart() =
+ flicker.assertLayersStart { isVisible(ComponentNameMatcher.LETTERBOX) }
+
+ fun assertLetterboxAppLayerKeepVisible() = flicker.layerKeepVisible(letterboxApp)
+
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.rotationTests] for configuring screen orientation and navigation
- * modes.
+ * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
+ * navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index f212a4e0417e..c2141a370f10 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -70,6 +70,10 @@ class OpenAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker)
@Test
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
+ @Postsubmit
+ @Test
+ fun appIsLetterboxedAtEnd() = assertAppLetterboxedAtEnd()
+
/**
* Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
* flicker, and disappears before the transition is complete
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index 8e75439889b2..b0e1a42306df 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -53,25 +53,32 @@ class RestartAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flick
get() = {
super.transition(this)
transitions { letterboxApp.clickRestart(wmHelper) }
- teardown { letterboxApp.exit(wmHelper) }
}
@Postsubmit @Test fun appVisibleAtStartAndEnd() = assertLetterboxAppVisibleAtStartAndEnd()
@Postsubmit
@Test
- fun appLayerVisibilityChanges() {
- flicker.assertLayers {
- this.isVisible(letterboxApp)
+ fun appWindowVisibilityChanges() {
+ flicker.assertWm {
+ this.isAppWindowVisible(letterboxApp)
.then()
- .isInvisible(letterboxApp)
+ .isAppWindowInvisible(letterboxApp) // animatingExit true
.then()
- .isVisible(letterboxApp)
+ .isAppWindowVisible(letterboxApp) // Activity finish relaunching
}
}
@Postsubmit
@Test
+ fun appLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
+
+ @Postsubmit
+ @Test
+ fun appIsLetterboxedAtStart() = assertAppLetterboxedAtStart()
+
+ @Postsubmit
+ @Test
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtStartHasRoundedCorners()
/** Checks that the visible region of [letterboxApp] is still within display bounds */
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index 93ee6992a98f..a4ac261d1946 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -54,7 +54,6 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 238367575)
class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiButtonTest(flicker) {
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit
@@ -71,7 +70,7 @@ class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiButtonT
transitions { tapl.goHome() }
}
- @FlakyTest(bugId = 256863309)
+ @Presubmit
@Test
override fun pipLayerReduces() {
flicker.assertLayers {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index d53eac073e6b..b7e73ad11c9f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -26,6 +26,7 @@ import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
@@ -34,6 +35,7 @@ import com.android.wm.shell.flicker.layerKeepVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsKeepVisible
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
+import com.android.wm.shell.flicker.splitscreen.benchmark.CopyContentInSplitBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,29 +51,19 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CopyContentInSplit(flicker: FlickerTest) : SplitScreenBase(flicker) {
- private val textEditApp = SplitScreenUtils.getIme(instrumentation)
- private val MagnifierLayer = ComponentNameMatcher("", "magnifier surface bbq wrapper#")
- private val PopupWindowLayer = ComponentNameMatcher("", "PopupWindow:")
-
+class CopyContentInSplit(override val flicker: FlickerTest) :
+ CopyContentInSplitBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, textEditApp) }
- transitions {
- SplitScreenUtils.copyContentInSplit(
- instrumentation,
- device,
- primaryApp,
- textEditApp
- )
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
@IwTest(focusArea = "sysui")
@Presubmit
@Test
- fun cujCompleted() {
+ override fun cujCompleted() {
flicker.appWindowIsVisibleAtStart(primaryApp)
flicker.appWindowIsVisibleAtStart(textEditApp)
flicker.splitScreenDividerIsVisibleAtStart()
@@ -128,8 +120,8 @@ class CopyContentInSplit(flicker: FlickerTest) : SplitScreenBase(flicker) {
ComponentNameMatcher.SNAPSHOT,
ComponentNameMatcher.IME_SNAPSHOT,
EdgeExtensionComponentMatcher(),
- MagnifierLayer,
- PopupWindowLayer
+ magnifierLayer,
+ popupWindowLayer
)
)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
index 1b55f3975e1c..3fd6d17f27cb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
@@ -17,22 +17,21 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesInvisible
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.layerBecomesInvisible
import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesInvisible
-import com.android.wm.shell.flicker.splitScreenDismissed
import com.android.wm.shell.flicker.splitScreenDividerBecomesInvisible
+import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByDividerBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -48,37 +47,16 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DismissSplitScreenByDivider(flicker: FlickerTest) : SplitScreenBase(flicker) {
+class DismissSplitScreenByDivider(override val flicker: FlickerTest) :
+ DismissSplitScreenByDividerBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
- transitions {
- if (tapl.isTablet) {
- SplitScreenUtils.dragDividerToDismissSplit(
- device,
- wmHelper,
- dragToRight = false,
- dragToBottom = true
- )
- } else {
- SplitScreenUtils.dragDividerToDismissSplit(
- device,
- wmHelper,
- dragToRight = true,
- dragToBottom = true
- )
- }
- wmHelper.StateSyncBuilder().withFullScreenApp(secondaryApp).waitForAndVerify()
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = false)
-
@Presubmit
@Test
fun splitScreenDividerBecomesInvisible() = flicker.splitScreenDividerBecomesInvisible()
@@ -176,12 +154,4 @@ class DismissSplitScreenByDivider(flicker: FlickerTest) : SplitScreenBase(flicke
@Test
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
- }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index 2e81b30d2e9a..e05b22141e4d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -17,18 +17,18 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesInvisible
import com.android.wm.shell.flicker.layerBecomesInvisible
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesInvisible
-import com.android.wm.shell.flicker.splitScreenDismissed
import com.android.wm.shell.flicker.splitScreenDividerBecomesInvisible
+import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByGoHomeBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,21 +44,14 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DismissSplitScreenByGoHome(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
+class DismissSplitScreenByGoHome(override val flicker: FlickerTest) :
+ DismissSplitScreenByGoHomeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
- transitions {
- tapl.goHome()
- wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = true)
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index 5180791276a2..0b0a3dad320b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -24,6 +24,7 @@ import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
@@ -32,8 +33,7 @@ import com.android.wm.shell.flicker.layerKeepVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsChanges
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
-import org.junit.Assume
-import org.junit.Before
+import com.android.wm.shell.flicker.splitscreen.benchmark.DragDividerToResizeBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,24 +49,19 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DragDividerToResize(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
+class DragDividerToResize(override val flicker: FlickerTest) :
+ DragDividerToResizeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
- transitions { SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper) }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @Before
- fun before() {
- Assume.assumeTrue(tapl.isTablet || !flicker.scenario.isLandscapeOrSeascapeAtStart)
- }
-
@IwTest(focusArea = "sysui")
@Presubmit
@Test
- fun cujCompleted() {
+ override fun cujCompleted() {
flicker.appWindowIsVisibleAtStart(primaryApp)
flicker.appWindowIsVisibleAtStart(secondaryApp)
flicker.splitScreenDividerIsVisibleAtStart()
@@ -74,9 +69,6 @@ class DragDividerToResize(flicker: FlickerTest) : SplitScreenBase(flicker) {
flicker.appWindowIsVisibleAtEnd(primaryApp)
flicker.appWindowIsVisibleAtEnd(secondaryApp)
flicker.splitScreenDividerIsVisibleAtEnd()
-
- // TODO(b/246490534): Add validation for resized app after withAppTransitionIdle is
- // robust enough to get the correct end state.
}
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
index 69da1e29a19c..e55868675da7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
@@ -26,6 +25,7 @@ import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
@@ -34,9 +34,7 @@ import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
-import org.junit.Assume
-import org.junit.Before
+import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromAllAppsBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -53,40 +51,15 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromAllApps(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
- @Before
- fun before() {
- Assume.assumeTrue(tapl.isTablet)
- }
-
+class EnterSplitScreenByDragFromAllApps(override val flicker: FlickerTest) :
+ EnterSplitScreenByDragFromAllAppsBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- tapl.goHome()
- primaryApp.launchViaIntent(wmHelper)
- }
- transitions {
- tapl.launchedAppState.taskbar
- .openAllApps()
- .getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
@FlakyTest(bugId = 245472831)
@Test
fun splitScreenDividerBecomesVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
index 1773846c18e9..ab8ecc54e71c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
@@ -26,6 +25,7 @@ import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.layerBecomesVisible
@@ -33,9 +33,7 @@ import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
-import org.junit.Assume
-import org.junit.Before
+import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromNotificationBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -52,39 +50,16 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromNotification(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
- private val sendNotificationApp = SplitScreenUtils.getSendNotification(instrumentation)
-
- @Before
- fun before() {
- Assume.assumeTrue(tapl.isTablet)
- }
-
+class EnterSplitScreenByDragFromNotification(override val flicker: FlickerTest) :
+ EnterSplitScreenByDragFromNotificationBenchmark(flicker), ICommonAssertions {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- // Send a notification
- sendNotificationApp.launchViaIntent(wmHelper)
- sendNotificationApp.postNotification(wmHelper)
- tapl.goHome()
- primaryApp.launchViaIntent(wmHelper)
- }
- transitions {
- SplitScreenUtils.dragFromNotificationToSplit(instrumentation, device, wmHelper)
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, sendNotificationApp)
- }
- teardown { sendNotificationApp.exit(wmHelper) }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(primaryApp, sendNotificationApp, fromOtherApp = false)
-
@FlakyTest(bugId = 245472831)
@Test
fun splitScreenDividerBecomesVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
index c1977e9e82f7..516ca97bc531 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -25,15 +24,14 @@ import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
-import org.junit.Assume
-import org.junit.Before
+import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromShortcutBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,42 +47,16 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromShortcut(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
- @Before
- fun before() {
- Assume.assumeTrue(tapl.isTablet)
- }
+class EnterSplitScreenByDragFromShortcut(override val flicker: FlickerTest) :
+ EnterSplitScreenByDragFromShortcutBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- tapl.goHome()
- SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
- primaryApp.launchViaIntent(wmHelper)
- }
- transitions {
- tapl.launchedAppState.taskbar
- .getAppIcon(secondaryApp.appName)
- .openDeepShortcutMenu()
- .getMenuItem("Split Screen Secondary Activity")
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
@Presubmit
@Test
fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
index 3bea66ef0a27..4af7e248b660 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
@@ -26,6 +25,7 @@ import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
@@ -34,9 +34,7 @@ import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
-import org.junit.Assume
-import org.junit.Before
+import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromTaskbarBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -53,41 +51,16 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromTaskbar(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
- @Before
- fun before() {
- Assume.assumeTrue(tapl.isTablet)
- }
-
+class EnterSplitScreenByDragFromTaskbar(override val flicker: FlickerTest) :
+ EnterSplitScreenByDragFromTaskbarBenchmark(flicker), ICommonAssertions {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- tapl.goHome()
- SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
- primaryApp.launchViaIntent(wmHelper)
- }
- transitions {
- tapl.launchedAppState.taskbar
- .getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
@FlakyTest(bugId = 245472831)
@Test
fun splitScreenDividerBecomesVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
index c45387722a49..faad9e82ffef 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
@@ -17,20 +17,20 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenFromOverviewBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -46,31 +46,15 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenFromOverview(flicker: FlickerTest) : SplitScreenBase(flicker) {
+class EnterSplitScreenFromOverview(override val flicker: FlickerTest) :
+ EnterSplitScreenFromOverviewBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- primaryApp.launchViaIntent(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- tapl.goHome()
- wmHelper
- .StateSyncBuilder()
- .withAppTransitionIdle()
- .withHomeActivityVisible()
- .waitForAndVerify()
- }
- transitions {
- SplitScreenUtils.splitFromOverview(tapl, device)
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
@Presubmit
@Test
fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
index 7abdc06820d6..195b73a14a72 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
@@ -20,25 +20,33 @@ import android.content.Context
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.wm.shell.flicker.BaseTest
+import com.android.wm.shell.flicker.BaseBenchmarkTest
-abstract class SplitScreenBase(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class SplitScreenBase(flicker: FlickerTest) : BaseBenchmarkTest(flicker) {
protected val context: Context = instrumentation.context
protected val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
protected val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- /** {@inheritDoc} */
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- tapl.setEnableRotation(true)
- setRotation(flicker.scenario.startRotation)
- tapl.setExpectedRotation(flicker.scenario.startRotation.value)
- tapl.workspace.switchToOverview().dismissAllTasks()
- }
- teardown {
- primaryApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
- }
+ protected open val defaultSetup: FlickerBuilder.() -> Unit = {
+ setup {
+ tapl.setEnableRotation(true)
+ setRotation(flicker.scenario.startRotation)
+ tapl.setExpectedRotation(flicker.scenario.startRotation.value)
+ tapl.workspace.switchToOverview().dismissAllTasks()
}
+ }
+
+ protected open val defaultTeardown: FlickerBuilder.() -> Unit = {
+ teardown {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+ }
+
+ protected open val withoutTracing: FlickerBuilder.() -> Unit = {
+ withoutLayerTracing()
+ withoutWindowManagerTracing()
+ withoutTransitionTracing()
+ withoutTransactionsTracing()
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index fbb7c7159234..8cf871f88314 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -20,14 +20,12 @@ import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
-import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.WindowManagerStateHelper
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
@@ -36,6 +34,7 @@ import com.android.wm.shell.flicker.layerKeepVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
+import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchAppByDoubleTapDividerBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,98 +50,19 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchAppByDoubleTapDivider(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
+class SwitchAppByDoubleTapDivider(override val flicker: FlickerTest) :
+ SwitchAppByDoubleTapDividerBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
- transitions {
- SplitScreenUtils.doubleTapDividerToSwitch(device)
- wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
-
- waitForLayersToSwitch(wmHelper)
- waitForWindowsToSwitch(wmHelper)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- private fun waitForWindowsToSwitch(wmHelper: WindowManagerStateHelper) {
- wmHelper
- .StateSyncBuilder()
- .add("appWindowsSwitched") {
- val primaryAppWindow =
- it.wmState.visibleWindows.firstOrNull { window ->
- primaryApp.windowMatchesAnyOf(window)
- }
- ?: return@add false
- val secondaryAppWindow =
- it.wmState.visibleWindows.firstOrNull { window ->
- secondaryApp.windowMatchesAnyOf(window)
- }
- ?: return@add false
-
- if (isLandscape(flicker.scenario.endRotation)) {
- return@add if (flicker.scenario.isTablet) {
- secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
- } else {
- primaryAppWindow.frame.right <= secondaryAppWindow.frame.left
- }
- } else {
- return@add if (flicker.scenario.isTablet) {
- primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
- } else {
- primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
- }
- }
- }
- .waitForAndVerify()
- }
-
- private fun waitForLayersToSwitch(wmHelper: WindowManagerStateHelper) {
- wmHelper
- .StateSyncBuilder()
- .add("appLayersSwitched") {
- val primaryAppLayer =
- it.layerState.visibleLayers.firstOrNull { window ->
- primaryApp.layerMatchesAnyOf(window)
- }
- ?: return@add false
- val secondaryAppLayer =
- it.layerState.visibleLayers.firstOrNull { window ->
- secondaryApp.layerMatchesAnyOf(window)
- }
- ?: return@add false
-
- val primaryVisibleRegion = primaryAppLayer.visibleRegion?.bounds ?: return@add false
- val secondaryVisibleRegion =
- secondaryAppLayer.visibleRegion?.bounds ?: return@add false
-
- if (isLandscape(flicker.scenario.endRotation)) {
- return@add if (flicker.scenario.isTablet) {
- secondaryVisibleRegion.right <= primaryVisibleRegion.left
- } else {
- primaryVisibleRegion.right <= secondaryVisibleRegion.left
- }
- } else {
- return@add if (flicker.scenario.isTablet) {
- primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
- } else {
- primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
- }
- }
- }
- .waitForAndVerify()
- }
-
- private fun isLandscape(rotation: Rotation): Boolean {
- val displayBounds = WindowUtils.getDisplayBounds(rotation)
- return displayBounds.width > displayBounds.height
- }
-
@IwTest(focusArea = "sysui")
@Presubmit
@Test
- fun cujCompleted() {
+ override fun cujCompleted() {
flicker.appWindowIsVisibleAtStart(primaryApp)
flicker.appWindowIsVisibleAtStart(secondaryApp)
flicker.splitScreenDividerIsVisibleAtStart()
@@ -150,9 +70,6 @@ class SwitchAppByDoubleTapDivider(flicker: FlickerTest) : SplitScreenBase(flicke
flicker.appWindowIsVisibleAtEnd(primaryApp)
flicker.appWindowIsVisibleAtEnd(secondaryApp)
flicker.splitScreenDividerIsVisibleAtEnd()
-
- // TODO(b/246490534): Add validation for switched app after withAppTransitionIdle is
- // robust enough to get the correct end state.
}
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
index d675bfb0119d..078d95de1dd0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -25,11 +24,12 @@ import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromAnotherAppBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,29 +45,15 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromAnotherApp(flicker: FlickerTest) : SplitScreenBase(flicker) {
- val thirdApp = SplitScreenUtils.getNonResizeable(instrumentation)
-
+class SwitchBackToSplitFromAnotherApp(override val flicker: FlickerTest) :
+ SwitchBackToSplitFromAnotherAppBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
-
- thirdApp.launchViaIntent(wmHelper)
- wmHelper.StateSyncBuilder().withWindowSurfaceAppeared(thirdApp).waitForAndVerify()
- }
- transitions {
- tapl.launchedAppState.quickSwitchToPreviousApp()
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
@Presubmit
@Test
fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
index 9f4cb8c381fc..7c84243e00d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -25,11 +24,12 @@ import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromHomeBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,28 +45,15 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromHome(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
+class SwitchBackToSplitFromHome(override val flicker: FlickerTest) :
+ SwitchBackToSplitFromHomeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
-
- tapl.goHome()
- wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
- }
- transitions {
- tapl.workspace.quickSwitchToPreviousApp()
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
@Presubmit
@Test
fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
index a33d8cab9fbd..7c46d3e099a2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -25,11 +24,12 @@ import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromRecentBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,28 +45,15 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromRecent(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
+class SwitchBackToSplitFromRecent(override val flicker: FlickerTest) :
+ SwitchBackToSplitFromRecentBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
-
- tapl.goHome()
- wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
- }
- transitions {
- tapl.workspace.switchToOverview().currentTask.open()
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
@Presubmit
@Test
fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
index 4c96b3a319d5..3b2da8dbcf9f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
@@ -24,6 +24,7 @@ import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowBecomesInvisible
import com.android.wm.shell.flicker.appWindowBecomesVisible
@@ -36,6 +37,7 @@ import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsSnapToDivider
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
+import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBetweenSplitPairsBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,32 +53,19 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBetweenSplitPairs(flicker: FlickerTest) : SplitScreenBase(flicker) {
- private val thirdApp = SplitScreenUtils.getIme(instrumentation)
- private val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
-
+class SwitchBetweenSplitPairs(override val flicker: FlickerTest) :
+ SwitchBetweenSplitPairsBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, thirdApp, fourthApp)
- SplitScreenUtils.waitForSplitComplete(wmHelper, thirdApp, fourthApp)
- }
- transitions {
- tapl.launchedAppState.quickSwitchToPreviousApp()
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
- teardown {
- thirdApp.exit(wmHelper)
- fourthApp.exit(wmHelper)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
@IwTest(focusArea = "sysui")
@Presubmit
@Test
- fun cujCompleted() {
+ override fun cujCompleted() {
flicker.appWindowIsVisibleAtStart(thirdApp)
flicker.appWindowIsVisibleAtStart(fourthApp)
flicker.splitScreenDividerIsVisibleAtStart()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
new file mode 100644
index 000000000000..a189a3f67eca
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class CopyContentInSplitBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val textEditApp = SplitScreenUtils.getIme(instrumentation)
+ protected val magnifierLayer = ComponentNameMatcher("", "magnifier surface bbq wrapper#")
+ protected val popupWindowLayer = ComponentNameMatcher("", "PopupWindow:")
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, textEditApp) }
+ transitions {
+ SplitScreenUtils.copyContentInSplit(
+ instrumentation,
+ device,
+ primaryApp,
+ textEditApp
+ )
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ open fun cujCompleted() {
+ // The validation of copied text is already done in SplitScreenUtils.copyContentInSplit()
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
new file mode 100644
index 000000000000..55ab7b3a30e4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenDismissed
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class DismissSplitScreenByDividerBenchmark(flicker: FlickerTest) : SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+ transitions {
+ if (tapl.isTablet) {
+ SplitScreenUtils.dragDividerToDismissSplit(
+ device,
+ wmHelper,
+ dragToRight = false,
+ dragToBottom = true
+ )
+ } else {
+ SplitScreenUtils.dragDividerToDismissSplit(
+ device,
+ wmHelper,
+ dragToRight = true,
+ dragToBottom = true
+ )
+ }
+ wmHelper.StateSyncBuilder().withFullScreenApp(secondaryApp).waitForAndVerify()
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = false)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
new file mode 100644
index 000000000000..c4cfd1add25c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenDismissed
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class DismissSplitScreenByGoHomeBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+ transitions {
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = true)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
new file mode 100644
index 000000000000..146287c21c75
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class DragDividerToResizeBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+ transitions { SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper) }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet || !flicker.scenario.isLandscapeOrSeascapeAtStart)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ open fun cujCompleted() {
+ // TODO(b/246490534): Add validation for resized app after withAppTransitionIdle is
+ // robust enough to get the correct end state.
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
new file mode 100644
index 000000000000..cc715021adf4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterSplitScreenByDragFromAllAppsBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ tapl.goHome()
+ primaryApp.launchViaIntent(wmHelper)
+ }
+ transitions {
+ tapl.launchedAppState.taskbar
+ .openAllApps()
+ .getAppIcon(secondaryApp.appName)
+ .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() =
+ flicker.splitScreenEntered(
+ primaryApp,
+ secondaryApp,
+ fromOtherApp = false,
+ appExistAtStart = false
+ )
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
new file mode 100644
index 000000000000..de78f09d3ef4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterSplitScreenByDragFromNotificationBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val sendNotificationApp = SplitScreenUtils.getSendNotification(instrumentation)
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ // Send a notification
+ sendNotificationApp.launchViaIntent(wmHelper)
+ sendNotificationApp.postNotification(wmHelper)
+ tapl.goHome()
+ primaryApp.launchViaIntent(wmHelper)
+ }
+ transitions {
+ SplitScreenUtils.dragFromNotificationToSplit(instrumentation, device, wmHelper)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, sendNotificationApp)
+ }
+ teardown { sendNotificationApp.exit(wmHelper) }
+ }
+
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() =
+ flicker.splitScreenEntered(primaryApp, sendNotificationApp, fromOtherApp = false)
+
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet)
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
new file mode 100644
index 000000000000..a29eb4085e54
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterSplitScreenByDragFromShortcutBenchmark(flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet)
+ }
+
+ protected val thisTransition: FlickerBuilder.() -> Unit = {
+ setup {
+ tapl.goHome()
+ SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
+ primaryApp.launchViaIntent(wmHelper)
+ }
+ transitions {
+ tapl.launchedAppState.taskbar
+ .getAppIcon(secondaryApp.appName)
+ .openDeepShortcutMenu()
+ .getMenuItem("Split Screen Secondary Activity")
+ .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() =
+ flicker.splitScreenEntered(
+ primaryApp,
+ secondaryApp,
+ fromOtherApp = false,
+ appExistAtStart = false
+ )
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
new file mode 100644
index 000000000000..b2395cafafc1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ tapl.goHome()
+ SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
+ primaryApp.launchViaIntent(wmHelper)
+ }
+ transitions {
+ tapl.launchedAppState.taskbar
+ .getAppIcon(secondaryApp.appName)
+ .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() =
+ flicker.splitScreenEntered(
+ primaryApp,
+ secondaryApp,
+ fromOtherApp = false,
+ appExistAtStart = false
+ )
+
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet)
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
new file mode 100644
index 000000000000..e1d85d0a4371
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterSplitScreenFromOverviewBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ primaryApp.launchViaIntent(wmHelper)
+ secondaryApp.launchViaIntent(wmHelper)
+ tapl.goHome()
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withHomeActivityVisible()
+ .waitForAndVerify()
+ }
+ transitions {
+ SplitScreenUtils.splitFromOverview(tapl, device)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
new file mode 100644
index 000000000000..ba8c46091808
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.helpers.WindowUtils
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class SwitchAppByDoubleTapDividerBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+ transitions {
+ SplitScreenUtils.doubleTapDividerToSwitch(device)
+ wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+
+ waitForLayersToSwitch(wmHelper)
+ waitForWindowsToSwitch(wmHelper)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ private fun waitForWindowsToSwitch(wmHelper: WindowManagerStateHelper) {
+ wmHelper
+ .StateSyncBuilder()
+ .add("appWindowsSwitched") {
+ val primaryAppWindow =
+ it.wmState.visibleWindows.firstOrNull { window ->
+ primaryApp.windowMatchesAnyOf(window)
+ }
+ ?: return@add false
+ val secondaryAppWindow =
+ it.wmState.visibleWindows.firstOrNull { window ->
+ secondaryApp.windowMatchesAnyOf(window)
+ }
+ ?: return@add false
+
+ if (isLandscape(flicker.scenario.endRotation)) {
+ return@add if (flicker.scenario.isTablet) {
+ secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
+ } else {
+ primaryAppWindow.frame.right <= secondaryAppWindow.frame.left
+ }
+ } else {
+ return@add if (flicker.scenario.isTablet) {
+ primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
+ } else {
+ primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
+ }
+ }
+ }
+ .waitForAndVerify()
+ }
+
+ private fun waitForLayersToSwitch(wmHelper: WindowManagerStateHelper) {
+ wmHelper
+ .StateSyncBuilder()
+ .add("appLayersSwitched") {
+ val primaryAppLayer =
+ it.layerState.visibleLayers.firstOrNull { window ->
+ primaryApp.layerMatchesAnyOf(window)
+ }
+ ?: return@add false
+ val secondaryAppLayer =
+ it.layerState.visibleLayers.firstOrNull { window ->
+ secondaryApp.layerMatchesAnyOf(window)
+ }
+ ?: return@add false
+
+ val primaryVisibleRegion = primaryAppLayer.visibleRegion?.bounds ?: return@add false
+ val secondaryVisibleRegion =
+ secondaryAppLayer.visibleRegion?.bounds ?: return@add false
+
+ if (isLandscape(flicker.scenario.endRotation)) {
+ return@add if (flicker.scenario.isTablet) {
+ secondaryVisibleRegion.right <= primaryVisibleRegion.left
+ } else {
+ primaryVisibleRegion.right <= secondaryVisibleRegion.left
+ }
+ } else {
+ return@add if (flicker.scenario.isTablet) {
+ primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
+ } else {
+ primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
+ }
+ }
+ }
+ .waitForAndVerify()
+ }
+
+ private fun isLandscape(rotation: Rotation): Boolean {
+ val displayBounds = WindowUtils.getDisplayBounds(rotation)
+ return displayBounds.width > displayBounds.height
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ open fun cujCompleted() {
+ // TODO(b/246490534): Add validation for switched app after withAppTransitionIdle is
+ // robust enough to get the correct end state.
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
new file mode 100644
index 000000000000..bbb2edc621e2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ private val thirdApp = SplitScreenUtils.getNonResizeable(instrumentation)
+
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+
+ thirdApp.launchViaIntent(wmHelper)
+ wmHelper.StateSyncBuilder().withWindowSurfaceAppeared(thirdApp).waitForAndVerify()
+ }
+ transitions {
+ tapl.launchedAppState.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
new file mode 100644
index 000000000000..fa382932eb88
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class SwitchBackToSplitFromHomeBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+ transitions {
+ tapl.workspace.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
new file mode 100644
index 000000000000..1064bd93e3c1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class SwitchBackToSplitFromRecentBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+ transitions {
+ tapl.workspace.switchToOverview().currentTask.open()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
new file mode 100644
index 000000000000..8f4393f8d20d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class SwitchBetweenSplitPairsBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thirdApp = SplitScreenUtils.getIme(instrumentation)
+ protected val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
+
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, thirdApp, fourthApp)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, thirdApp, fourthApp)
+ }
+ transitions {
+ tapl.launchedAppState.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ teardown {
+ thirdApp.exit(wmHelper)
+ fourthApp.exit(wmHelper)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui") @Presubmit @Test open fun cujCompleted() {}
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index 57a698128d77..ad4d97f6fe40 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -47,7 +47,7 @@ android_test {
"truth-prebuilt",
"testables",
"platform-test-annotations",
- "frameworks-base-testutils",
+ "servicestests-utils",
],
libs: [
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 f506969f51df..1335ebf105a6 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
@@ -31,6 +31,7 @@ import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_FRONT
+import android.window.DisplayAreaInfo
import android.window.TransitionRequestInfo
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
@@ -344,6 +345,57 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ fun moveToNextDisplay_noOtherDisplays() {
+ whenever(rootTaskDisplayAreaOrganizer.displayIds).thenReturn(intArrayOf(DEFAULT_DISPLAY))
+ val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
+ controller.moveToNextDisplay(task.taskId)
+ verifyWCTNotExecuted()
+ }
+
+ @Test
+ fun moveToNextDisplay_moveFromFirstToSecondDisplay() {
+ // Set up two display ids
+ whenever(rootTaskDisplayAreaOrganizer.displayIds)
+ .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
+ // Create a mock for the target display area: second display
+ val secondDisplayArea = DisplayAreaInfo(MockToken().token(), SECOND_DISPLAY, 0)
+ whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(SECOND_DISPLAY))
+ .thenReturn(secondDisplayArea)
+
+ val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
+ controller.moveToNextDisplay(task.taskId)
+ with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
+ assertThat(hierarchyOps).hasSize(1)
+ assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder())
+ assertThat(hierarchyOps[0].isReparent).isTrue()
+ assertThat(hierarchyOps[0].newParent).isEqualTo(secondDisplayArea.token.asBinder())
+ assertThat(hierarchyOps[0].toTop).isTrue()
+ }
+ }
+
+ @Test
+ fun moveToNextDisplay_moveFromSecondToFirstDisplay() {
+ // Set up two display ids
+ whenever(rootTaskDisplayAreaOrganizer.displayIds)
+ .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
+ // Create a mock for the target display area: default display
+ val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
+ whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
+ .thenReturn(defaultDisplayArea)
+
+ val task = setUpFreeformTask(displayId = SECOND_DISPLAY)
+ controller.moveToNextDisplay(task.taskId)
+
+ with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
+ assertThat(hierarchyOps).hasSize(1)
+ assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder())
+ assertThat(hierarchyOps[0].isReparent).isTrue()
+ assertThat(hierarchyOps[0].newParent).isEqualTo(defaultDisplayArea.token.asBinder())
+ assertThat(hierarchyOps[0].toTop).isTrue()
+ }
+ }
+
+ @Test
fun getTaskWindowingMode() {
val fullscreenTask = setUpFullscreenTask()
val freeformTask = setUpFreeformTask()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
index 6199e0b05059..8592dea19289 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
@@ -94,7 +94,7 @@ public class EnterDesktopTaskTransitionHandlerTest {
WindowContainerTransaction wct = new WindowContainerTransaction();
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
- mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+ mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
@@ -115,7 +115,7 @@ public class EnterDesktopTaskTransitionHandlerTest {
WindowContainerTransaction wct = new WindowContainerTransaction();
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
- mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+ mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
index 4fad05433d1c..265b10df1945 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
@@ -100,7 +100,7 @@ public class ExitDesktopTaskTransitionHandlerTest extends ShellTestCase {
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mExitDesktopTaskTransitionHandler);
- mExitDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+ mExitDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FULLSCREEN);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
index 523cb6629d9a..54f36f61859d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
@@ -48,6 +48,7 @@ import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
@@ -71,6 +72,8 @@ public class DragAndDropControllerTest extends ShellTestCase {
@Mock
private ShellController mShellController;
@Mock
+ private ShellCommandHandler mShellCommandHandler;
+ @Mock
private DisplayController mDisplayController;
@Mock
private UiEventLogger mUiEventLogger;
@@ -89,7 +92,8 @@ public class DragAndDropControllerTest extends ShellTestCase {
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mController = new DragAndDropController(mContext, mShellInit, mShellController,
- mDisplayController, mUiEventLogger, mIconProvider, mMainExecutor);
+ mShellCommandHandler, mDisplayController, mUiEventLogger, mIconProvider,
+ mMainExecutor);
mController.onInit();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index e6219d1aa792..d27064d1b4da 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -152,10 +152,15 @@ public class StageCoordinatorTests extends ShellTestCase {
when(mStageCoordinator.isSplitActive()).thenReturn(true);
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
- final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final WindowContainerTransaction wct = spy(new WindowContainerTransaction());
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
- verify(mSideStage).addTask(eq(task), eq(wct));
+ verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
+ verify(mMainStage).reparentTopTask(eq(wct));
+ verify(mMainStage).evictAllChildren(eq(wct));
+ verify(mSideStage).evictAllChildren(eq(wct));
+ verify(mSplitLayout).resetDividerPosition();
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
}
@@ -171,14 +176,11 @@ public class StageCoordinatorTests extends ShellTestCase {
final WindowContainerTransaction wct = new WindowContainerTransaction();
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
- verify(mMainStage).addTask(eq(task), eq(wct));
+ verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
+ verify(mMainStage).evictAllChildren(eq(wct));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
-
- mStageCoordinator.moveToStage(task, SPLIT_POSITION_TOP_OR_LEFT, wct);
- verify(mSideStage).addTask(eq(task), eq(wct));
- assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
- assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index bf62acfc47a1..8115a5d4e89c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -265,17 +265,17 @@ public class StartingSurfaceDrawerTests extends ShellTestCase {
mStartingSurfaceDrawer.mWindowRecords.addRecord(taskId,
new StartingSurfaceDrawer.StartingWindowRecord() {
@Override
- public void removeIfPossible(StartingWindowRemovalInfo info,
+ public boolean removeIfPossible(StartingWindowRemovalInfo info,
boolean immediately) {
-
+ return true;
}
});
mStartingSurfaceDrawer.mWindowlessRecords.addRecord(taskId,
new StartingSurfaceDrawer.StartingWindowRecord() {
@Override
- public void removeIfPossible(StartingWindowRemovalInfo info,
+ public boolean removeIfPossible(StartingWindowRemovalInfo info,
boolean immediately) {
-
+ return true;
}
});
mStartingSurfaceDrawer.clearAllWindows();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
index 45590951dd1d..9d566860c1cd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
@@ -179,4 +179,23 @@ public class TaskViewTransitionsTest extends ShellTestCase {
mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_CHANGE);
assertThat(pendingBounds2).isNull();
}
+
+ @Test
+ public void testSetTaskVisibility_taskRemoved_noNPE() {
+ mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
+
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, false);
+ }
+
+ @Test
+ public void testSetTaskBounds_taskRemoved_noNPE() {
+ mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
+
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
+ new Rect(0, 0, 100, 100));
+ }
}
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 8eb5c6a08d88..963632b1f8f6 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
@@ -17,6 +17,7 @@
package com.android.wm.shell.transition;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -50,6 +51,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.after;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
@@ -58,14 +60,19 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.IApplicationThread;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Pair;
+import android.view.IRecentsAnimationRunner;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -86,6 +93,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.server.testutils.StubTransaction;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.TransitionInfoBuilder;
@@ -93,6 +101,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.recents.RecentsTransitionHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.sysui.ShellSharedConstants;
@@ -100,6 +109,7 @@ import com.android.wm.shell.sysui.ShellSharedConstants;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.InOrder;
import java.util.ArrayList;
@@ -162,8 +172,8 @@ public class ShellTransitionTests extends ShellTestCase {
verify(mOrganizer, times(1)).startTransition(eq(transitToken), any());
TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken, info, new StubTransaction(),
+ new StubTransaction());
assertEquals(1, mDefaultHandler.activeCount());
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
@@ -212,8 +222,8 @@ public class ShellTransitionTests extends ShellTestCase {
transitions.requestStartTransition(transitToken,
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
verify(mOrganizer, times(1)).startTransition(eq(transitToken), isNull());
- transitions.onTransitionReady(transitToken, open, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken, open, new StubTransaction(),
+ new StubTransaction());
assertEquals(1, mDefaultHandler.activeCount());
assertEquals(0, testHandler.activeCount());
mDefaultHandler.finishAll();
@@ -228,8 +238,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_OPEN, mwTaskInfo, null /* remote */));
verify(mOrganizer, times(1)).startTransition(
eq(transitToken), eq(handlerWCT));
- transitions.onTransitionReady(transitToken, open, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken, open, new StubTransaction(),
+ new StubTransaction());
assertEquals(1, mDefaultHandler.activeCount());
assertEquals(0, testHandler.activeCount());
mDefaultHandler.finishAll();
@@ -246,8 +256,8 @@ public class ShellTransitionTests extends ShellTestCase {
eq(transitToken), eq(handlerWCT));
TransitionInfo change = new TransitionInfoBuilder(TRANSIT_CHANGE)
.addChange(TRANSIT_CHANGE).build();
- transitions.onTransitionReady(transitToken, change, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken, change, new StubTransaction(),
+ new StubTransaction());
assertEquals(0, mDefaultHandler.activeCount());
assertEquals(1, testHandler.activeCount());
assertEquals(0, topHandler.activeCount());
@@ -284,8 +294,8 @@ public class ShellTransitionTests extends ShellTestCase {
verify(mOrganizer, times(1)).startTransition(eq(transitToken), any());
TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken, info, new StubTransaction(),
+ new StubTransaction());
assertEquals(0, mDefaultHandler.activeCount());
assertTrue(remoteCalled[0]);
mDefaultHandler.finishAll();
@@ -434,8 +444,8 @@ public class ShellTransitionTests extends ShellTestCase {
verify(mOrganizer, times(1)).startTransition(eq(transitToken), any());
TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken, info, new StubTransaction(),
+ new StubTransaction());
assertEquals(0, mDefaultHandler.activeCount());
assertTrue(remoteCalled[0]);
mDefaultHandler.finishAll();
@@ -484,10 +494,10 @@ public class ShellTransitionTests extends ShellTestCase {
oneShot.setTransition(transitToken);
IBinder anotherToken = new Binder();
assertFalse(oneShot.startAnimation(anotherToken, new TransitionInfo(transitType, 0),
- mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class),
+ new StubTransaction(), new StubTransaction(),
testFinish));
assertTrue(oneShot.startAnimation(transitToken, new TransitionInfo(transitType, 0),
- mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class),
+ new StubTransaction(), new StubTransaction(),
testFinish));
}
@@ -501,8 +511,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(transitToken1, info1, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken1, info1, new StubTransaction(),
+ new StubTransaction());
assertEquals(1, mDefaultHandler.activeCount());
IBinder transitToken2 = new Binder();
@@ -510,8 +520,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(transitToken2, info2, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken2, info2, new StubTransaction(),
+ new StubTransaction());
// default handler doesn't merge by default, so it shouldn't increment active count.
assertEquals(1, mDefaultHandler.activeCount());
assertEquals(0, mDefaultHandler.mergeCount());
@@ -542,8 +552,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(transitToken1, info1, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken1, info1, new StubTransaction(),
+ new StubTransaction());
assertEquals(1, mDefaultHandler.activeCount());
IBinder transitToken2 = new Binder();
@@ -551,8 +561,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(transitToken2, info2, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken2, info2, new StubTransaction(),
+ new StubTransaction());
// it should still only have 1 active, but then show 1 merged
assertEquals(1, mDefaultHandler.activeCount());
assertEquals(1, mDefaultHandler.mergeCount());
@@ -611,8 +621,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(token, info, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(token, info, new StubTransaction(),
+ new StubTransaction());
return token;
};
@@ -678,8 +688,8 @@ public class ShellTransitionTests extends ShellTestCase {
// queued), so continue the transition lifecycle for that.
TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken, info, new StubTransaction(),
+ new StubTransaction());
// At this point, if things are not working, we'd get an NPE due to attempting to merge
// into the shellInit transition which hasn't started yet.
assertEquals(1, mDefaultHandler.activeCount());
@@ -791,8 +801,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(transitToken1, info1, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken1, info1, new StubTransaction(),
+ new StubTransaction());
assertEquals(1, mDefaultHandler.activeCount());
transitions.runOnIdle(runnable2);
@@ -806,8 +816,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- transitions.onTransitionReady(transitToken2, info2, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken2, info2, new StubTransaction(),
+ new StubTransaction());
assertEquals(1, mDefaultHandler.activeCount());
mDefaultHandler.finishAll();
@@ -858,8 +868,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
- SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction startT = new StubTransaction();
+ SurfaceControl.Transaction finishT = new StubTransaction();
transitions.onTransitionReady(transitToken, info, startT, finishT);
InOrder observerOrder = inOrder(observer);
@@ -883,8 +893,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class);
- SurfaceControl.Transaction finishT1 = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction startT1 = new StubTransaction();
+ SurfaceControl.Transaction finishT1 = new StubTransaction();
transitions.onTransitionReady(transitToken1, info1, startT1, finishT1);
verify(observer).onTransitionReady(transitToken1, info1, startT1, finishT1);
@@ -893,8 +903,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class);
- SurfaceControl.Transaction finishT2 = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction startT2 = new StubTransaction();
+ SurfaceControl.Transaction finishT2 = new StubTransaction();
transitions.onTransitionReady(transitToken2, info2, startT2, finishT2);
verify(observer, times(1)).onTransitionReady(transitToken2, info2, startT2, finishT2);
verify(observer, times(0)).onTransitionStarting(transitToken2);
@@ -927,8 +937,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class);
- SurfaceControl.Transaction finishT1 = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction startT1 = new StubTransaction();
+ SurfaceControl.Transaction finishT1 = new StubTransaction();
transitions.onTransitionReady(transitToken1, info1, startT1, finishT1);
IBinder transitToken2 = new Binder();
@@ -936,8 +946,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
- SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class);
- SurfaceControl.Transaction finishT2 = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction startT2 = new StubTransaction();
+ SurfaceControl.Transaction finishT2 = new StubTransaction();
transitions.onTransitionReady(transitToken2, info2, startT2, finishT2);
InOrder observerOrder = inOrder(observer);
@@ -999,8 +1009,8 @@ public class ShellTransitionTests extends ShellTestCase {
new TransitionRequestInfo(TRANSIT_CHANGE, mwTaskInfo, null /* remote */));
TransitionInfo change = new TransitionInfoBuilder(TRANSIT_CHANGE)
.addChange(TRANSIT_CHANGE).build();
- SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class);
- SurfaceControl.Transaction finishT1 = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction startT1 = new StubTransaction();
+ SurfaceControl.Transaction finishT1 = new StubTransaction();
transitions.onTransitionReady(transitToken1, change, startT1, finishT1);
// Request the second transition that should be handled by the default handler
@@ -1009,8 +1019,8 @@ public class ShellTransitionTests extends ShellTestCase {
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
transitions.requestStartTransition(transitToken2,
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
- SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class);
- SurfaceControl.Transaction finishT2 = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction startT2 = new StubTransaction();
+ SurfaceControl.Transaction finishT2 = new StubTransaction();
transitions.onTransitionReady(transitToken2, open, startT2, finishT2);
verify(observer).onTransitionReady(transitToken2, open, startT2, finishT2);
verify(observer, times(0)).onTransitionStarting(transitToken2);
@@ -1019,8 +1029,8 @@ public class ShellTransitionTests extends ShellTestCase {
IBinder transitToken3 = new Binder();
transitions.requestStartTransition(transitToken3,
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
- SurfaceControl.Transaction startT3 = mock(SurfaceControl.Transaction.class);
- SurfaceControl.Transaction finishT3 = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction startT3 = new StubTransaction();
+ SurfaceControl.Transaction finishT3 = new StubTransaction();
transitions.onTransitionReady(transitToken3, open, startT3, finishT3);
verify(observer, times(0)).onTransitionStarting(transitToken2);
verify(observer).onTransitionReady(transitToken3, open, startT3, finishT3);
@@ -1045,6 +1055,104 @@ public class ShellTransitionTests extends ShellTestCase {
}
@Test
+ public void testTransitSleep_squashesRecents() {
+ ShellInit shellInit = new ShellInit(mMainExecutor);
+ final Transitions transitions =
+ new Transitions(mContext, shellInit, mock(ShellController.class), mOrganizer,
+ mTransactionPool, createTestDisplayController(), mMainExecutor,
+ mMainHandler, mAnimExecutor);
+ final RecentsTransitionHandler recentsHandler =
+ new RecentsTransitionHandler(shellInit, transitions, null);
+ transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+ shellInit.init();
+
+ Transitions.TransitionObserver observer = mock(Transitions.TransitionObserver.class);
+ transitions.registerObserver(observer);
+
+ RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS);
+ RunningTaskInfo task2 = createTaskInfo(2);
+
+ // Start an open transition for the purpose of occupying the ready queue
+ final IBinder transitOpen1 = new Binder("transitOpen1");
+ final TransitionInfo infoOpen1 =
+ new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN, task1)
+ .build();
+ mMainExecutor.execute(() -> {
+ transitions.requestStartTransition(transitOpen1, new TransitionRequestInfo(
+ TRANSIT_OPEN, task1 /* trigger */, null /* remote */));
+ onTransitionReady(transitions, transitOpen1, infoOpen1);
+ });
+
+ // First transition on the queue should start immediately.
+ mMainExecutor.flushAll();
+ verify(observer).onTransitionReady(eq(transitOpen1), any(), any(), any());
+ verify(observer).onTransitionStarting(eq(transitOpen1));
+
+ // Start recents
+ final IRecentsAnimationRunner recentsListener =
+ mock(IRecentsAnimationRunner.class, Answers.RETURNS_DEEP_STUBS);
+ final IBinder transitRecents = recentsHandler.startRecentsTransition(
+ mock(PendingIntent.class) /* intent */,
+ mock(Intent.class) /* fillIn */,
+ new Bundle() /* options */,
+ mock(IApplicationThread.class) /* appThread */,
+ recentsListener);
+ final TransitionInfo infoRecents =
+ new TransitionInfoBuilder(TRANSIT_TO_FRONT)
+ .addChange(TRANSIT_TO_FRONT, task1)
+ .addChange(TRANSIT_CLOSE, task2)
+ .build();
+ onTransitionReady(transitions, transitRecents, infoRecents);
+
+ // Start another open transition during recents
+ final IBinder transitOpen2 = new Binder("transitOpen2");
+ final TransitionInfo infoOpen2 =
+ new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN, task2)
+ .addChange(TRANSIT_TO_BACK, task1)
+ .build();
+ mMainExecutor.execute(() -> {
+ transitions.requestStartTransition(transitOpen2, new TransitionRequestInfo(
+ TRANSIT_OPEN, task2 /* trigger */, null /* remote */));
+ onTransitionReady(transitions, transitOpen2, infoOpen2);
+ });
+
+ // Finish testOpen1 to start processing the other transitions
+ mMainExecutor.execute(() -> {
+ mDefaultHandler.finishOne();
+ });
+ mMainExecutor.flushAll();
+
+ // Recents transition SHOULD start, and merge the open transition, which should NOT start.
+ verify(observer).onTransitionFinished(eq(transitOpen1), eq(false) /* aborted */);
+ verify(observer).onTransitionReady(eq(transitRecents), any(), any(), any());
+ verify(observer).onTransitionStarting(eq(transitRecents));
+ verify(observer).onTransitionReady(eq(transitOpen2), any(), any(), any());
+ verify(observer).onTransitionMerged(eq(transitOpen2), eq(transitRecents));
+ // verify(observer).onTransitionFinished(eq(transitOpen2), eq(true) /* aborted */);
+
+ // Go to sleep
+ final IBinder transitSleep = new Binder("transitSleep");
+ final TransitionInfo infoSleep = new TransitionInfoBuilder(TRANSIT_SLEEP).build();
+ mMainExecutor.execute(() -> {
+ transitions.requestStartTransition(transitSleep, new TransitionRequestInfo(
+ TRANSIT_SLEEP, null /* trigger */, null /* remote */));
+ onTransitionReady(transitions, transitSleep, infoSleep);
+ });
+ mMainExecutor.flushAll();
+
+ // Recents transition should finish itself when it sees the sleep transition coming.
+ verify(observer).onTransitionFinished(eq(transitRecents), eq(false));
+ verify(observer).onTransitionFinished(eq(transitSleep), eq(false));
+ }
+
+ private void onTransitionReady(Transitions transitions, IBinder token, TransitionInfo info) {
+ transitions.onTransitionReady(token, info, new StubTransaction(),
+ new StubTransaction());
+ }
+
+ @Test
public void testEmptyTransitionStillReportsKeyguardGoingAway() {
Transitions transitions = createTestTransitions();
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
@@ -1056,8 +1164,8 @@ public class ShellTransitionTests extends ShellTestCase {
// Make a no-op transition
TransitionInfo info = new TransitionInfoBuilder(
TRANSIT_OPEN, TRANSIT_FLAG_KEYGUARD_GOING_AWAY, true /* noOp */).build();
- transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class),
- mock(SurfaceControl.Transaction.class));
+ transitions.onTransitionReady(transitToken, info, new StubTransaction(),
+ new StubTransaction());
// If keyguard-going-away flag set, then it shouldn't be aborted.
assertEquals(1, mDefaultHandler.activeCount());
@@ -1397,7 +1505,7 @@ public class ShellTransitionTests extends ShellTestCase {
private static void onTransitionReady(Transitions transitions, IBinder token) {
transitions.onTransitionReady(token, createTransitionInfo(),
- mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class));
+ new StubTransaction(), new StubTransaction());
}
private static TransitionInfo createTransitionInfo() {
@@ -1414,15 +1522,15 @@ public class ShellTransitionTests extends ShellTestCase {
private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode, int activityType) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
+ taskInfo.topActivityType = activityType;
taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
taskInfo.configuration.windowConfiguration.setActivityType(activityType);
+ taskInfo.token = mock(WindowContainerToken.class);
return taskInfo;
}
private static RunningTaskInfo createTaskInfo(int taskId) {
- RunningTaskInfo taskInfo = new RunningTaskInfo();
- taskInfo.taskId = taskId;
- return taskInfo;
+ return createTaskInfo(taskId, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
}
private DisplayController createTestDisplayController() {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
new file mode 100644
index 000000000000..348b3659e864
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.windowdecor
+
+import android.app.ActivityManager
+import android.graphics.PointF
+import android.graphics.Rect
+import android.os.IBinder
+import android.testing.AndroidTestingRunner
+import android.view.Display
+import android.window.WindowContainerToken
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.Mockito.any
+import org.mockito.MockitoAnnotations
+
+/**
+ * Tests for [DragPositioningCallbackUtility].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:DragPositioningCallbackUtilityTest
+ */
+@RunWith(AndroidTestingRunner::class)
+class DragPositioningCallbackUtilityTest {
+ @Mock
+ private lateinit var mockWindowDecoration: WindowDecoration<*>
+ @Mock
+ private lateinit var taskToken: WindowContainerToken
+ @Mock
+ private lateinit var taskBinder: IBinder
+ @Mock
+ private lateinit var mockDisplayController: DisplayController
+ @Mock
+ private lateinit var mockDisplayLayout: DisplayLayout
+ @Mock
+ private lateinit var mockDisplay: Display
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(taskToken.asBinder()).thenReturn(taskBinder)
+ whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+ whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+ }
+
+ mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
+ taskId = TASK_ID
+ token = taskToken
+ minWidth = MIN_WIDTH
+ minHeight = MIN_HEIGHT
+ defaultMinSize = DEFAULT_MIN
+ displayId = DISPLAY_ID
+ configuration.windowConfiguration.bounds = STARTING_BOUNDS
+ }
+ mockWindowDecoration.mDisplay = mockDisplay
+ whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+ }
+
+ @Test
+ fun testChangeBoundsDoesNotChangeHeightWhenLessThanMin() {
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect()
+
+ // Resize to width of 95px and height of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 95
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
+
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right - 5)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ fun testChangeBoundsDoesNotChangeWidthWhenLessThanMin() {
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect()
+
+ // Resize to height of 95px and width of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 95
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
+
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top + 5)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ fun testChangeBoundsDoesNotChangeHeightWhenNegative() {
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect()
+
+ // Resize to width of 95px and width of -5px with minimum of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 105
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
+
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right - 5)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ fun testChangeBoundsRunsWhenResizeBoundsValid() {
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect()
+
+ // Shrink to height 20px and width 20px with both min height/width equal to 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 80
+ val newY = STARTING_BOUNDS.top.toFloat() + 80
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top + 80)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right - 80)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ fun testChangeBoundsDoesNotRunWithNegativeHeightAndWidth() {
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect()
+ // Shrink to height -5px and width -5px with both min height/width equal to 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 105
+ val newY = STARTING_BOUNDS.top.toFloat() + 105
+
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ fun testChangeBounds_toDisallowedBounds_freezesAtLimit() {
+ var hasMoved = false
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat())
+ val repositionTaskBounds = Rect()
+ // Initial resize to width and height 110px.
+ var newX = STARTING_BOUNDS.right.toFloat() + 10
+ var newY = STARTING_BOUNDS.bottom.toFloat() + 10
+ var delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+ assertTrue(DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
+ hasMoved, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration))
+ hasMoved = true
+ // Resize width to 120px, height to disallowed area which should not result in a change.
+ newX += 10
+ newY = DISALLOWED_RESIZE_AREA.top.toFloat()
+ delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+ assertTrue(DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
+ hasMoved, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration))
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right + 20)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom + 10)
+ }
+
+ companion object {
+ private const val TASK_ID = 5
+ private const val MIN_WIDTH = 10
+ private const val MIN_HEIGHT = 10
+ private const val DENSITY_DPI = 20
+ private const val DEFAULT_MIN = 40
+ private const val DISPLAY_ID = 1
+ private const val NAVBAR_HEIGHT = 50
+ private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
+ private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+ private val DISALLOWED_RESIZE_AREA = Rect(
+ DISPLAY_BOUNDS.left,
+ DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
+ DISPLAY_BOUNDS.right,
+ DISPLAY_BOUNDS.bottom)
+ private val STABLE_BOUNDS = Rect(
+ DISPLAY_BOUNDS.left,
+ DISPLAY_BOUNDS.top,
+ DISPLAY_BOUNDS.right,
+ DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
+ )
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 84ccddeb6a76..5bea8f2d1c45 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -14,7 +14,6 @@ import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
@@ -22,7 +21,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when`
+import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
@@ -72,10 +71,10 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
mockDragStartListener
)
- `when`(taskToken.asBinder()).thenReturn(taskBinder)
- `when`(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
- `when`(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
- `when`(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ whenever(taskToken.asBinder()).thenReturn(taskBinder)
+ whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+ whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(STABLE_BOUNDS)
}
@@ -89,7 +88,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
configuration.windowConfiguration.bounds = STARTING_BOUNDS
}
mockWindowDecoration.mDisplay = mockDisplay
- `when`(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+ whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
}
@Test
@@ -237,293 +236,6 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
})
}
- @Test
- fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenLessThanMin() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Resize to width of 95px and height of 5px with min width of 10px
- val newX = STARTING_BOUNDS.right.toFloat() - 5
- val newY = STARTING_BOUNDS.top.toFloat() + 95
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
- != 0) && change.configuration.windowConfiguration.bounds.top ==
- STARTING_BOUNDS.top &&
- change.configuration.windowConfiguration.bounds.bottom ==
- STARTING_BOUNDS.bottom
- }
- })
- }
-
- @Test
- fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenLessThanMin() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Resize to height of 95px and width of 5px with min width of 10px
- val newX = STARTING_BOUNDS.right.toFloat() - 95
- val newY = STARTING_BOUNDS.top.toFloat() + 5
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
- != 0) && change.configuration.windowConfiguration.bounds.right ==
- STARTING_BOUNDS.right &&
- change.configuration.windowConfiguration.bounds.left ==
- STARTING_BOUNDS.left
- }
- })
- }
-
- @Test
- fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenNegative() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Resize to height of -5px and width of 95px
- val newX = STARTING_BOUNDS.right.toFloat() - 5
- val newY = STARTING_BOUNDS.top.toFloat() + 105
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
- != 0) && change.configuration.windowConfiguration.bounds.top ==
- STARTING_BOUNDS.top &&
- change.configuration.windowConfiguration.bounds.bottom ==
- STARTING_BOUNDS.bottom
- }
- })
- }
-
- @Test
- fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenNegative() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Resize to width of -5px and height of 95px
- val newX = STARTING_BOUNDS.right.toFloat() - 105
- val newY = STARTING_BOUNDS.top.toFloat() + 5
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
- != 0) && change.configuration.windowConfiguration.bounds.right ==
- STARTING_BOUNDS.right &&
- change.configuration.windowConfiguration.bounds.left ==
- STARTING_BOUNDS.left
- }
- })
- }
-
- @Test
- fun testDragResize_resize_setBoundsRunsWhenResizeBoundsValid() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Shrink to height 20px and width 20px with both min height/width equal to 10px
- val newX = STARTING_BOUNDS.right.toFloat() - 80
- val newY = STARTING_BOUNDS.top.toFloat() + 80
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
- }
- })
- }
-
- @Test
- fun testDragResize_resize_setBoundsDoesNotRunWithNegativeHeightAndWidth() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Shrink to height 5px and width 5px with both min height/width equal to 10px
- val newX = STARTING_BOUNDS.right.toFloat() - 95
- val newY = STARTING_BOUNDS.top.toFloat() + 95
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
- }
- })
- }
-
- @Test
- fun testDragResize_resize_useDefaultMinWhenMinWidthInvalid() {
- mockWindowDecoration.mTaskInfo.minWidth = -1
-
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Shrink to width and height of 3px with invalid minWidth = -1 and defaultMinSize = 5px
- val newX = STARTING_BOUNDS.right.toFloat() - 97
- val newY = STARTING_BOUNDS.top.toFloat() + 97
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
- }
- })
- }
-
- @Test
- fun testDragResize_resize_useMinWidthWhenValid() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Shrink to width and height of 7px with valid minWidth = 10px and defaultMinSize = 5px
- val newX = STARTING_BOUNDS.right.toFloat() - 93
- val newY = STARTING_BOUNDS.top.toFloat() + 93
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
- }
- })
- }
-
- fun testDragResize_toDisallowedBounds_freezesAtLimit() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, // Resize right-bottom corner
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.bottom.toFloat()
- )
-
- // Resize the task by 10px to the right and bottom, a valid destination
- val newBounds = Rect(
- STARTING_BOUNDS.left,
- STARTING_BOUNDS.top,
- STARTING_BOUNDS.right + 10,
- STARTING_BOUNDS.bottom + 10)
- taskPositioner.onDragPositioningMove(
- newBounds.right.toFloat(),
- newBounds.bottom.toFloat()
- )
-
- // Resize the task by another 10px to the right (allowed) and to just in the disallowed
- // area of the Y coordinate.
- val newBounds2 = Rect(
- newBounds.left,
- newBounds.top,
- newBounds.right + 10,
- DISALLOWED_RESIZE_AREA.top
- )
- taskPositioner.onDragPositioningMove(
- newBounds2.right.toFloat(),
- newBounds2.bottom.toFloat()
- )
-
- taskPositioner.onDragPositioningEnd(newBounds2.right.toFloat(), newBounds2.bottom.toFloat())
-
- // The first resize falls in the allowed area, verify there's a change for it.
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder && change.ofBounds(newBounds)
- }
- })
- // The second resize falls in the disallowed area, verify there's no change for it.
- verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder && change.ofBounds(newBounds2)
- }
- })
- // Instead, there should be a change for its allowed portion (the X movement) with the Y
- // staying frozen in the last valid resize position.
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder && change.ofBounds(
- Rect(
- newBounds2.left,
- newBounds2.top,
- newBounds2.right,
- newBounds.bottom // Stayed at the first resize destination.
- )
- )
- }
- })
- }
-
private fun WindowContainerTransaction.Change.ofBounds(bounds: Rect): Boolean {
return ((windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) &&
bounds == configuration.windowConfiguration.bounds
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index bf365ca782ee..498082bd53e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -34,7 +34,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when`
+import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
@@ -85,10 +85,10 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
mockDragStartListener
)
- `when`(taskToken.asBinder()).thenReturn(taskBinder)
- `when`(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
- `when`(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
- `when`(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ whenever(taskToken.asBinder()).thenReturn(taskBinder)
+ whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+ whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(STABLE_BOUNDS)
}
@@ -102,7 +102,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
configuration.windowConfiguration.bounds = STARTING_BOUNDS
}
mockDesktopWindowDecoration.mDisplay = mockDisplay
- `when`(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+ whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
}
@Test
diff --git a/libs/hwui/Tonemapper.cpp b/libs/hwui/Tonemapper.cpp
index 0d39f0e33298..974a5d05aa84 100644
--- a/libs/hwui/Tonemapper.cpp
+++ b/libs/hwui/Tonemapper.cpp
@@ -97,7 +97,6 @@ void tonemapPaint(const SkImageInfo& source, const SkImageInfo& destination, flo
.inputDataspace = sourceDataspace,
.outputDataspace = destinationDataspace,
.undoPremultipliedAlpha = source.alphaType() == kPremul_SkAlphaType,
- .fakeInputDataspace = destinationDataspace,
.type = shaders::LinearEffect::SkSLType::ColorFilter};
constexpr float kMaxDisplayBrightnessNits = 1000.f;
constexpr float kCurrentDisplayBrightnessNits = 500.f;
diff --git a/libs/hwui/effects/GainmapRenderer.cpp b/libs/hwui/effects/GainmapRenderer.cpp
index bfe4eaf39e21..613f52b32bea 100644
--- a/libs/hwui/effects/GainmapRenderer.cpp
+++ b/libs/hwui/effects/GainmapRenderer.cpp
@@ -38,7 +38,7 @@ namespace android::uirenderer {
using namespace renderthread;
-static float getTargetHdrSdrRatio(const SkColorSpace* destColorspace) {
+float getTargetHdrSdrRatio(const SkColorSpace* destColorspace) {
// We should always have a known destination colorspace. If we don't we must be in some
// legacy mode where we're lost and also definitely not going to HDR
if (destColorspace == nullptr) {
diff --git a/libs/hwui/effects/GainmapRenderer.h b/libs/hwui/effects/GainmapRenderer.h
index 4ed2445da17e..0ab03f0b571a 100644
--- a/libs/hwui/effects/GainmapRenderer.h
+++ b/libs/hwui/effects/GainmapRenderer.h
@@ -25,6 +25,8 @@
namespace android::uirenderer {
+float getTargetHdrSdrRatio(const SkColorSpace* destColorspace);
+
void DrawGainmapBitmap(SkCanvas* c, const sk_sp<const SkImage>& image, const SkRect& src,
const SkRect& dst, const SkSamplingOptions& sampling, const SkPaint* paint,
SkCanvas::SrcRectConstraint constraint,
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index a4960ea17c79..c58ba6868eb5 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -26,6 +26,7 @@
#include "SkM44.h"
#include "include/gpu/GpuTypes.h" // from Skia
#include "utils/GLUtils.h"
+#include <effects/GainmapRenderer.h>
namespace android {
namespace uirenderer {
@@ -129,6 +130,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
info.height = fboSize.height();
mat4.getColMajor(&info.transform[0]);
info.color_space_ptr = canvas->imageInfo().colorSpace();
+ info.currentHdrSdrRatio = getTargetHdrSdrRatio(info.color_space_ptr);
// ensure that the framebuffer that the webview will render into is bound before we clear
// the stencil and/or draw the functor.
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index e6ef95b9cf91..e299d12b1d67 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -30,6 +30,7 @@
#include "renderthread/VulkanManager.h"
#include "thread/ThreadBase.h"
#include "utils/TimeUtils.h"
+#include "effects/GainmapRenderer.h"
namespace android {
namespace uirenderer {
@@ -73,6 +74,7 @@ void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) {
.clip_right = mClip.fRight,
.clip_bottom = mClip.fBottom,
.is_layer = !vulkan_info.fFromSwapchainOrAndroidWindow,
+ .currentHdrSdrRatio = getTargetHdrSdrRatio(mImageInfo.colorSpace()),
};
mat4.getColMajor(&params.transform[0]);
params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer;
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index e168a7b9459a..adf3c06b8624 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -32,6 +32,7 @@
#include "renderthread/EglManager.h"
#include "thread/ThreadBase.h"
#include "utils/TimeUtils.h"
+#include "effects/GainmapRenderer.h"
#include <SkBlendMode.h>
@@ -139,6 +140,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
info.height = mFBInfo.height();
mat4.getColMajor(&info.transform[0]);
info.color_space_ptr = canvas->imageInfo().colorSpace();
+ info.currentHdrSdrRatio = getTargetHdrSdrRatio(info.color_space_ptr);
glViewport(0, 0, info.width, info.height);
diff --git a/libs/hwui/private/hwui/DrawGlInfo.h b/libs/hwui/private/hwui/DrawGlInfo.h
index 501b8df9bc36..7888c8719e88 100644
--- a/libs/hwui/private/hwui/DrawGlInfo.h
+++ b/libs/hwui/private/hwui/DrawGlInfo.h
@@ -86,6 +86,11 @@ struct DrawGlInfo {
// commands are issued.
kStatusDrew = 0x4
};
+
+ // The current HDR/SDR ratio that we are rendering to. The transform to SDR will already
+ // be baked into the color_space_ptr, so this is just to indicate the amount of extended
+ // range is available if desired
+ float currentHdrSdrRatio;
}; // struct DrawGlInfo
} // namespace uirenderer
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
index 5c596576df4e..8f7063d72314 100644
--- a/libs/hwui/private/hwui/DrawVkInfo.h
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -71,6 +71,11 @@ struct VkFunctorDrawParams {
// Input: Whether destination surface is offscreen surface.
bool is_layer;
+
+ // The current HDR/SDR ratio that we are rendering to. The transform to SDR will already
+ // be baked into the color_space_ptr, so this is just to indicate the amount of extended
+ // range is available if desired
+ float currentHdrSdrRatio;
};
} // namespace uirenderer
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 7e9d44fbdbd1..c00a2707e0a2 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -29,6 +29,7 @@
#include "Layer.h"
#include "Properties.h"
#include "RenderThread.h"
+#include "VulkanManager.h"
#include "pipeline/skia/ATraceMemoryDump.h"
#include "pipeline/skia/ShaderCache.h"
#include "pipeline/skia/SkiaMemoryTracer.h"
@@ -182,8 +183,14 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState)
}
log.appendFormat("Contexts: %zu (stopped = %zu)\n", mCanvasContexts.size(), stoppedContexts);
+ auto vkInstance = VulkanManager::peekInstance();
if (!mGrContext) {
- log.appendFormat("No GPU context.\n");
+ if (!vkInstance) {
+ log.appendFormat("No GPU context.\n");
+ } else {
+ log.appendFormat("No GrContext; however %d remaining Vulkan refs",
+ vkInstance->getStrongCount() - 1);
+ }
return;
}
std::vector<skiapipeline::ResourcePair> cpuResourceMap = {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 96bfc1061d4e..4cffc6c2efe3 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -42,7 +42,7 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-static std::array<std::string_view, 18> sEnableExtensions{
+static std::array<std::string_view, 19> sEnableExtensions{
VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
@@ -56,6 +56,7 @@ static std::array<std::string_view, 18> sEnableExtensions{
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME,
+ VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME,
VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
@@ -106,11 +107,11 @@ GrVkGetProc VulkanManager::sSkiaGetProp = [](const char* proc_name, VkInstance i
#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
-sp<VulkanManager> VulkanManager::getInstance() {
- // cache a weakptr to the context to enable a second thread to share the same vulkan state
- static wp<VulkanManager> sWeakInstance = nullptr;
- static std::mutex sLock;
+// cache a weakptr to the context to enable a second thread to share the same vulkan state
+static wp<VulkanManager> sWeakInstance = nullptr;
+static std::mutex sLock;
+sp<VulkanManager> VulkanManager::getInstance() {
std::lock_guard _lock{sLock};
sp<VulkanManager> vulkanManager = sWeakInstance.promote();
if (!vulkanManager.get()) {
@@ -121,6 +122,11 @@ sp<VulkanManager> VulkanManager::getInstance() {
return vulkanManager;
}
+sp<VulkanManager> VulkanManager::peekInstance() {
+ std::lock_guard _lock{sLock};
+ return sWeakInstance.promote();
+}
+
VulkanManager::~VulkanManager() {
if (mDevice != VK_NULL_HANDLE) {
mDeviceWaitIdle(mDevice);
@@ -403,9 +409,13 @@ void VulkanManager::initialize() {
}
}
-sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options,
- ContextType contextType) {
+static void onGrContextReleased(void* context) {
+ VulkanManager* manager = (VulkanManager*)context;
+ manager->decStrong((void*)onGrContextReleased);
+}
+sk_sp<GrDirectContext> VulkanManager::createContext(GrContextOptions& options,
+ ContextType contextType) {
GrVkBackendContext backendContext;
backendContext.fInstance = mInstance;
backendContext.fPhysicalDevice = mPhysicalDevice;
@@ -417,6 +427,11 @@ sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& opti
backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
backendContext.fGetProc = sSkiaGetProp;
+ LOG_ALWAYS_FATAL_IF(options.fContextDeleteProc != nullptr, "Conflicting fContextDeleteProcs!");
+ this->incStrong((void*)onGrContextReleased);
+ options.fContextDeleteContext = this;
+ options.fContextDeleteProc = onGrContextReleased;
+
return GrDirectContext::MakeVulkan(backendContext, options);
}
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index c5196eeccea3..00a40c0c85c3 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -66,6 +66,7 @@ class RenderThread;
class VulkanManager final : public RefBase {
public:
static sp<VulkanManager> getInstance();
+ static sp<VulkanManager> peekInstance();
// Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must
// be call once before use of the VulkanManager. Multiple calls after the first will simiply
@@ -109,7 +110,7 @@ public:
};
// returns a Skia graphic context used to draw content on the specified thread
- sk_sp<GrDirectContext> createContext(const GrContextOptions& options,
+ sk_sp<GrDirectContext> createContext(GrContextOptions& options,
ContextType contextType = ContextType::kRenderThread);
uint32_t getDriverVersion() const { return mDriverVersion; }
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index bffe137c2bd3..913af8ac3474 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -284,7 +284,9 @@ sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
case HAL_DATASPACE_TRANSFER_GAMMA2_8:
return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
case HAL_DATASPACE_TRANSFER_ST2084:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+ return SkColorSpace::MakeRGB({-2.0, -1.555223, 1.860454, 32 / 2523.0, 2413 / 128.0,
+ -2392 / 128.0, 8192 / 1305.0},
+ gamut);
case HAL_DATASPACE_TRANSFER_SMPTE_170M:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
@@ -427,10 +429,10 @@ skcms_TransferFunction GetExtendedTransferFunction(float sdrHdrRatio) {
}
// Skia skcms' default HLG maps encoded [0, 1] to linear [1, 12] in order to follow ARIB
-// but LinearEffect expects a decoded [0, 1] range instead to follow Rec 2100.
+// but LinearEffect expects to map 1.0 == 203 nits
std::optional<skcms_TransferFunction> GetHLGScaleTransferFunction() {
skcms_TransferFunction hlgFn;
- if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 1.f / 12.f, 2.f, 2.f, 1.f / 0.17883277f,
+ if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 0.314509843, 2.f, 2.f, 1.f / 0.17883277f,
0.28466892f, 0.55991073f)) {
return std::make_optional<skcms_TransferFunction>(hlgFn);
}
diff --git a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
index 6092ac53ec39..82fc33edf08a 100644
--- a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
@@ -15,8 +15,8 @@
*/
package android.media.soundtrigger_middleware;
-import android.media.soundtrigger.RecognitionEvent;
-import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
/**
* Main interface for a client to get notifications of events coming from this module.
@@ -31,7 +31,7 @@ oneway interface ISoundTriggerCallback {
* In case of abortion, the caller may retry after the next onRecognitionAvailabilityChange()
* callback.
*/
- void onRecognition(int modelHandle, in RecognitionEvent event, int captureSession);
+ void onRecognition(int modelHandle, in RecognitionEventSys event, int captureSession);
/**
* Invoked whenever a phrase recognition event is triggered (typically, on recognition, but
* also in case of external aborting of a recognition or a forced recognition event - see the
@@ -39,7 +39,7 @@ oneway interface ISoundTriggerCallback {
* In case of abortion, the caller may retry after the next onRecognitionAvailabilityChange()
* callback.
*/
- void onPhraseRecognition(int modelHandle, in PhraseRecognitionEvent event, int captureSession);
+ void onPhraseRecognition(int modelHandle, in PhraseRecognitionEventSys event, int captureSession);
/**
* Notifies the client that some start/load operations that have previously failed for resource
* reasons (threw a ServiceSpecificException(RESOURCE_CONTENTION) or have been preempted) may
diff --git a/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEventSys.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEventSys.aidl
new file mode 100644
index 000000000000..6c912ed7e056
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEventSys.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger_middleware;
+
+import android.media.soundtrigger.PhraseRecognitionEvent;
+
+/**
+ * Wrapper to android.media.soundtrigger.RecognitionEvent providing additional fields used by the
+ * framework.
+ */
+parcelable PhraseRecognitionEventSys {
+
+ PhraseRecognitionEvent phraseRecognitionEvent;
+ /**
+ * Timestamp of when the trigger event from SoundTriggerHal was received by the
+ * framework.
+ *
+ * <p>same units and timebase as {@link SystemClock#elapsedRealtime()}.
+ * The value will be -1 if the event was not generated from the HAL.
+ */
+ // @ElapsedRealtimeLong
+ long halEventReceivedMillis = -1;
+}
diff --git a/media/aidl/android/media/soundtrigger_middleware/RecognitionEventSys.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionEventSys.aidl
new file mode 100644
index 000000000000..84e327d5df8c
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/RecognitionEventSys.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger_middleware;
+
+import android.media.soundtrigger.RecognitionEvent;
+
+/**
+ * Wrapper to android.media.soundtrigger.RecognitionEvent providing additional fields used by the
+ * framework.
+ */
+parcelable RecognitionEventSys {
+
+ RecognitionEvent recognitionEvent;
+ /**
+ * Timestamp of when the trigger event from SoundTriggerHal was received by the
+ * framework.
+ *
+ * <p>same units and timebase as {@link SystemClock#elapsedRealtime()}.
+ * The value will be -1 if the event was not generated from the HAL.
+ */
+ // @ElapsedRealtimeLong
+ long halEventReceivedMillis = -1;
+}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index e73cf87ba9f3..3123ee6dd4d7 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1237,6 +1237,9 @@ public class AudioSystem
public static final Set<Integer> DEVICE_IN_ALL_SCO_SET;
/** @hide */
public static final Set<Integer> DEVICE_IN_ALL_USB_SET;
+ /** @hide */
+ public static final Set<Integer> DEVICE_IN_ALL_BLE_SET;
+
static {
DEVICE_IN_ALL_SET = new HashSet<>();
DEVICE_IN_ALL_SET.add(DEVICE_IN_COMMUNICATION);
@@ -1276,6 +1279,66 @@ public class AudioSystem
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_ACCESSORY);
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_DEVICE);
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
+
+ DEVICE_IN_ALL_BLE_SET = new HashSet<>();
+ DEVICE_IN_ALL_BLE_SET.add(DEVICE_IN_BLE_HEADSET);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothDevice(int deviceType) {
+ return isBluetoothA2dpOutDevice(deviceType)
+ || isBluetoothScoDevice(deviceType)
+ || isBluetoothLeDevice(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothOutDevice(int deviceType) {
+ return isBluetoothA2dpOutDevice(deviceType)
+ || isBluetoothScoOutDevice(deviceType)
+ || isBluetoothLeOutDevice(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothInDevice(int deviceType) {
+ return isBluetoothScoInDevice(deviceType)
+ || isBluetoothLeInDevice(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothA2dpOutDevice(int deviceType) {
+ return DEVICE_OUT_ALL_A2DP_SET.contains(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothScoOutDevice(int deviceType) {
+ return DEVICE_OUT_ALL_SCO_SET.contains(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothScoInDevice(int deviceType) {
+ return DEVICE_IN_ALL_SCO_SET.contains(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothScoDevice(int deviceType) {
+ return isBluetoothScoOutDevice(deviceType)
+ || isBluetoothScoInDevice(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothLeOutDevice(int deviceType) {
+ return DEVICE_OUT_ALL_BLE_SET.contains(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothLeInDevice(int deviceType) {
+ return DEVICE_IN_ALL_BLE_SET.contains(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothLeDevice(int deviceType) {
+ return isBluetoothLeOutDevice(deviceType)
+ || isBluetoothLeInDevice(deviceType);
}
/** @hide */
diff --git a/media/java/android/media/soundtrigger/SoundTriggerInstrumentation.java b/media/java/android/media/soundtrigger/SoundTriggerInstrumentation.java
index 80bc5c07dd66..3dfc58788e8a 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerInstrumentation.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerInstrumentation.java
@@ -231,9 +231,17 @@ public final class SoundTriggerInstrumentation {
*/
public void setModelCallback(@NonNull @CallbackExecutor Executor executor, @NonNull
ModelCallback callback) {
+ Objects.requireNonNull(callback);
+ Objects.requireNonNull(executor);
synchronized (SoundTriggerInstrumentation.this.mLock) {
- mModelCallback = Objects.requireNonNull(callback);
- mModelExecutor = Objects.requireNonNull(executor);
+ if (mModelCallback == null) {
+ for (var droppedConsumer : mDroppedConsumerList) {
+ executor.execute(() -> droppedConsumer.accept(callback));
+ }
+ mDroppedConsumerList.clear();
+ }
+ mModelCallback = callback;
+ mModelExecutor = executor;
}
}
@@ -267,9 +275,11 @@ public final class SoundTriggerInstrumentation {
private void wrap(Consumer<ModelCallback> consumer) {
synchronized (SoundTriggerInstrumentation.this.mLock) {
- if (mModelCallback != null && mModelExecutor != null) {
+ if (mModelCallback != null) {
final ModelCallback callback = mModelCallback;
mModelExecutor.execute(() -> consumer.accept(callback));
+ } else {
+ mDroppedConsumerList.add(consumer);
}
}
}
@@ -282,6 +292,8 @@ public final class SoundTriggerInstrumentation {
private ModelCallback mModelCallback = null;
@GuardedBy("SoundTriggerInstrumentation.this.mLock")
private Executor mModelExecutor = null;
+ @GuardedBy("SoundTriggerInstrumentation.this.mLock")
+ private final List<Consumer<ModelCallback>> mDroppedConsumerList = new ArrayList<>();
}
/**
@@ -374,9 +386,18 @@ public final class SoundTriggerInstrumentation {
*/
public void setRecognitionCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull RecognitionCallback callback) {
+ Objects.requireNonNull(callback);
+ Objects.requireNonNull(executor);
synchronized (SoundTriggerInstrumentation.this.mLock) {
+ if (mRecognitionCallback == null) {
+ for (var droppedConsumer : mDroppedConsumerList) {
+ executor.execute(() -> droppedConsumer.accept(callback));
+ }
+ mDroppedConsumerList.clear();
+ }
mRecognitionCallback = callback;
mRecognitionExecutor = executor;
+
}
}
@@ -401,9 +422,11 @@ public final class SoundTriggerInstrumentation {
private void wrap(Consumer<RecognitionCallback> consumer) {
synchronized (SoundTriggerInstrumentation.this.mLock) {
- if (mRecognitionCallback != null && mRecognitionExecutor != null) {
+ if (mRecognitionCallback != null) {
final RecognitionCallback callback = mRecognitionCallback;
mRecognitionExecutor.execute(() -> consumer.accept(callback));
+ } else {
+ mDroppedConsumerList.add(consumer);
}
}
}
@@ -416,6 +439,8 @@ public final class SoundTriggerInstrumentation {
private Executor mRecognitionExecutor = null;
@GuardedBy("SoundTriggerInstrumentation.this.mLock")
private RecognitionCallback mRecognitionCallback = null;
+ @GuardedBy("SoundTriggerInstrumentation.this.mLock")
+ private final List<Consumer<RecognitionCallback>> mDroppedConsumerList = new ArrayList<>();
}
// Implementation of injection interface passed to the HAL.
diff --git a/native/android/activity_manager.cpp b/native/android/activity_manager.cpp
index 155a355241c8..bc6a84f01517 100644
--- a/native/android/activity_manager.cpp
+++ b/native/android/activity_manager.cpp
@@ -45,7 +45,7 @@ struct UidObserver : public BnUidObserver, public virtual IBinder::DeathRecipien
void onUidIdle(uid_t uid, bool disabled) override;
void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
int32_t capability) override;
- void onUidProcAdjChanged(uid_t uid) override;
+ void onUidProcAdjChanged(uid_t uid, int32_t adj) override;
// IBinder::DeathRecipient implementation
void binderDied(const wp<IBinder>& who) override;
@@ -121,7 +121,7 @@ void UidObserver::onUidActive(uid_t uid __unused) {}
void UidObserver::onUidIdle(uid_t uid __unused, bool disabled __unused) {}
-void UidObserver::onUidProcAdjChanged(uid_t uid __unused) {}
+void UidObserver::onUidProcAdjChanged(uid_t uid __unused, int32_t adj __unused) {}
void UidObserver::onUidStateChanged(uid_t uid, int32_t procState,
int64_t procStateSeq __unused,
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
index 5f067e9836a2..b888739016c7 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
@@ -60,6 +60,7 @@ public class SlicePurchaseActivity extends Activity {
@NonNull private Intent mIntent;
@NonNull private URL mUrl;
@TelephonyManager.PremiumCapability protected int mCapability;
+ private boolean mIsUserTriggeredFinish;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -71,6 +72,7 @@ public class SlicePurchaseActivity extends Activity {
SlicePurchaseController.PREMIUM_CAPABILITY_INVALID);
String url = mIntent.getStringExtra(SlicePurchaseController.EXTRA_PURCHASE_URL);
mApplicationContext = getApplicationContext();
+ mIsUserTriggeredFinish = true;
logd("onCreate: subId=" + subId + ", capability="
+ TelephonyManager.convertPremiumCapabilityToString(mCapability) + ", url=" + url);
@@ -153,12 +155,20 @@ public class SlicePurchaseActivity extends Activity {
@Override
protected void onDestroy() {
- logd("onDestroy: User canceled the purchase by closing the application.");
- SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponse(
- mIntent, SlicePurchaseController.EXTRA_INTENT_CANCELED);
+ if (mIsUserTriggeredFinish) {
+ logd("onDestroy: User canceled the purchase by closing the application.");
+ SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponse(
+ mIntent, SlicePurchaseController.EXTRA_INTENT_CANCELED);
+ }
super.onDestroy();
}
+ @Override
+ public void finishAndRemoveTask() {
+ mIsUserTriggeredFinish = false;
+ super.finishAndRemoveTask();
+ }
+
private void setupWebView() {
// Create WebView
mWebView = new WebView(this);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
index f594bf270d29..7ed18163dd83 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
@@ -123,12 +123,11 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
viewHolder.mExpandButton.setTag(R.drawable.btn_expand_more);
}
- setAccessibility(view, viewType,
- AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_expand, 0);
-
// Add expand buttons if the permissions are more than PERMISSION_SIZE in this list also
// make the summary invisible by default.
if (mPermissions.size() > PERMISSION_SIZE) {
+ setAccessibility(view, viewType,
+ AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_expand, 0);
viewHolder.mPermissionSummary.setVisibility(View.GONE);
diff --git a/packages/CredentialManager/AndroidManifest.xml b/packages/CredentialManager/AndroidManifest.xml
index 8724d69258ed..4161601e2317 100644
--- a/packages/CredentialManager/AndroidManifest.xml
+++ b/packages/CredentialManager/AndroidManifest.xml
@@ -42,15 +42,6 @@
android:excludeFromRecents="true"
android:theme="@style/Theme.CredentialSelector">
</activity>
-
- <receiver
- android:name=".CredentialProviderReceiver"
- android:exported="true"
- android:permission="android.permission.LAUNCH_CREDENTIAL_SELECTOR">
- <intent-filter>
- <action android:name="android.credentials.ui.action.CREDMAN_ENABLED_PROVIDERS_UPDATED"/>
- </intent-filter>
- </receiver>
</application>
</manifest>
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 340285760cda..6df07786f514 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -24,8 +24,8 @@
<string name="string_cancel">Cancel</string>
<!-- This is a label for a button that takes user to the next screen. [CHAR LIMIT=20] -->
<string name="string_continue">Continue</string>
- <!-- This is a label for a button that links to different places where the user can save their passkeys. [CHAR LIMIT=20] -->
- <string name="string_more_options">More options</string>
+ <!-- This is a label for a button that leads to a holistic view of all different options where the user can save their new app credential. [CHAR LIMIT=20] -->
+ <string name="string_more_options">Save another way</string>
<!-- This is a label for a button that links to additional information about passkeys. [CHAR LIMIT=20] -->
<string name="string_learn_more">Learn more</string>
<!-- This is a label for content description for show password icon button. -->
@@ -78,8 +78,12 @@
<!-- This text is followed by a list of one or more options. [CHAR LIMIT=200] -->
<string name="save_credential_to_title">Save <xliff:g id="credentialTypes" example="passkey">%1$s</xliff:g> to</string>
- <!-- This appears as the title of the modal bottom sheet for users to choose to create a passkey on another device. [CHAR LIMIT=200] -->
- <string name="create_passkey_in_other_device_title">Create passkey in another device?</string>
+ <!-- This appears as the title of the modal bottom sheet for users to confirm to create a passkey on another device. [CHAR LIMIT=200] -->
+ <string name="create_passkey_in_other_device_title">Create passkey on another device?</string>
+ <!-- This appears as the title of the modal bottom sheet for users to confirm to save a password on another device. [CHAR LIMIT=200] -->
+ <string name="save_password_on_other_device_title">Save password on another device?</string>
+ <!-- This appears as the title of the modal bottom sheet for users to confirm to save a sign-in credential on another device. [CHAR LIMIT=200] -->
+ <string name="save_sign_in_on_other_device_title">Save sign-in on another device?</string>
<!-- This appears as the title of the modal bottom sheet for users to confirm whether they should use the selected provider as default or not. [CHAR LIMIT=200] -->
<string name="use_provider_for_all_title">Use <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%1$s</xliff:g> for all your sign-ins?</string>
<!-- This appears as the description body of the modal bottom sheet for users to confirm whether they should use the selected provider as default or not. [CHAR LIMIT=300] -->
@@ -116,6 +120,8 @@
<!-- Strings for the get flow. -->
<!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved passkey to sign in to the app. [CHAR LIMIT=200] -->
<string name="get_dialog_title_use_passkey_for">Use your saved passkey for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
+ <!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved password to sign in to the app. [CHAR LIMIT=200] -->
+ <string name="get_dialog_title_use_password_for">Use your saved password for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
<!-- This appears as the title of the dialog asking for user confirmation to use the single user credential (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] -->
<string name="get_dialog_title_use_sign_in_for">Use your sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
<!-- This appears as the title of the dialog asking for user to make a choice from various available user credentials (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] -->
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index a9bee039264e..693e76731834 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -107,7 +107,6 @@ class CredentialManagerRepo(
initialUiState = when (requestInfo?.type) {
RequestInfo.TYPE_CREATE -> {
- val defaultProviderIdSetByUser = userConfigRepo.getDefaultProviderId()
val isPasskeyFirstUse = userConfigRepo.getIsPasskeyFirstUse()
val providerEnableListUiState = getCreateProviderEnableListInitialUiState()
val providerDisableListUiState = getCreateProviderDisableListInitialUiState()
@@ -119,7 +118,8 @@ class CredentialManagerRepo(
disabledProviders = providerDisableListUiState,
defaultProviderIdPreferredByApp =
requestDisplayInfoUiState.appPreferredDefaultProviderId,
- defaultProviderIdSetByUser = defaultProviderIdSetByUser,
+ defaultProviderIdsSetByUser =
+ requestDisplayInfoUiState.userSetDefaultProviderIds,
requestDisplayInfo = requestDisplayInfoUiState,
isOnPasskeyIntroStateAlready = false,
isPasskeyFirstUse = isPasskeyFirstUse,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialProviderReceiver.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialProviderReceiver.kt
deleted file mode 100644
index ee8cffed7f7d..000000000000
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialProviderReceiver.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.credentialmanager
-
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.util.Log
-import com.android.credentialmanager.common.Constants
-
-
-class CredentialProviderReceiver : BroadcastReceiver() {
-
- override fun onReceive(context: Context?, intent: Intent?) {
- Log.d(Constants.LOG_TAG, "Received intent in CredentialProviderReceiver")
-
- val sharedPreferences = context?.getSharedPreferences(context?.packageName,
- Context.MODE_PRIVATE)
- sharedPreferences?.edit()?.remove(UserConfigRepo.DEFAULT_PROVIDER)?.commit()
- }
-} \ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 6549b2d0187c..54a8678df9cc 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -25,6 +25,7 @@ import android.os.Bundle
import android.os.ResultReceiver
import android.util.Log
import androidx.activity.ComponentActivity
+import androidx.activity.OnBackPressedCallback
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.viewModels
@@ -48,9 +49,12 @@ import com.android.credentialmanager.ui.theme.PlatformTheme
class CredentialSelectorActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ Log.d(Constants.LOG_TAG, "Creating new CredentialSelectorActivity")
overrideActivityTransition(Activity.OVERRIDE_TRANSITION_OPEN,
0, 0)
- Log.d(Constants.LOG_TAG, "Creating new CredentialSelectorActivity")
+ overrideActivityTransition(Activity.OVERRIDE_TRANSITION_CLOSE,
+ 0, 0)
+
try {
val (isCancellationRequest, shouldShowCancellationUi, _) =
maybeCancelUIUponRequest(intent)
@@ -59,6 +63,18 @@ class CredentialSelectorActivity : ComponentActivity() {
}
val userConfigRepo = UserConfigRepo(this)
val credManRepo = CredentialManagerRepo(this, intent, userConfigRepo)
+
+ val backPressedCallback = object : OnBackPressedCallback(
+ true // default to enabled
+ ) {
+ override fun handleOnBackPressed() {
+ credManRepo.onUserCancel()
+ Log.d(Constants.LOG_TAG, "Activity back triggered: finish the activity.")
+ this@CredentialSelectorActivity.finish()
+ }
+ }
+ onBackPressedDispatcher.addCallback(this, backPressedCallback)
+
setContent {
PlatformTheme {
CredentialManagerBottomSheet(
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index 8b74d766a152..de679895eedb 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -255,7 +255,8 @@ class CredentialSelectorViewModel(
disabledProviders = prevUiState.disabledProviders,
defaultProviderIdPreferredByApp =
prevUiState.requestDisplayInfo.appPreferredDefaultProviderId,
- defaultProviderIdSetByUser = userConfigRepo.getDefaultProviderId(),
+ defaultProviderIdsSetByUser =
+ prevUiState.requestDisplayInfo.userSetDefaultProviderIds,
requestDisplayInfo = prevUiState.requestDisplayInfo,
isOnPasskeyIntroStateAlready = true,
isPasskeyFirstUse = userConfigRepo.getIsPasskeyFirstUse()
@@ -269,28 +270,10 @@ class CredentialSelectorViewModel(
userConfigRepo.setIsPasskeyFirstUse(false)
}
- fun createFlowOnMoreOptionsSelectedOnProviderSelection() {
- uiState = uiState.copy(
- createCredentialUiState = uiState.createCredentialUiState?.copy(
- currentScreenState = CreateScreenState.MORE_OPTIONS_SELECTION,
- isFromProviderSelection = true
- )
- )
- }
-
fun createFlowOnMoreOptionsSelectedOnCreationSelection() {
uiState = uiState.copy(
createCredentialUiState = uiState.createCredentialUiState?.copy(
currentScreenState = CreateScreenState.MORE_OPTIONS_SELECTION,
- isFromProviderSelection = false
- )
- )
- }
-
- fun createFlowOnBackProviderSelectionButtonSelected() {
- uiState = uiState.copy(
- createCredentialUiState = uiState.createCredentialUiState?.copy(
- currentScreenState = CreateScreenState.PROVIDER_SELECTION,
)
)
}
@@ -315,7 +298,10 @@ class CredentialSelectorViewModel(
uiState = uiState.copy(
createCredentialUiState = uiState.createCredentialUiState?.copy(
currentScreenState =
- if (activeEntry.activeProvider.id == userConfigRepo.getDefaultProviderId() ||
+ if (uiState.createCredentialUiState?.requestDisplayInfo?.userSetDefaultProviderIds
+ ?.contains(activeEntry.activeProvider.id) ?: true ||
+ !(uiState.createCredentialUiState?.foundCandidateFromUserDefaultProvider
+ ?: false) ||
!TextUtils.isEmpty(uiState.createCredentialUiState?.requestDisplayInfo
?.appPreferredDefaultProviderId))
CreateScreenState.CREATION_OPTION_SELECTION
@@ -325,18 +311,7 @@ class CredentialSelectorViewModel(
)
}
- fun createFlowOnEntrySelectedFromFirstUseScreen(activeEntry: ActiveEntry) {
- val providerId = activeEntry.activeProvider.id
- createFlowOnDefaultChanged(providerId)
- uiState = uiState.copy(
- createCredentialUiState = uiState.createCredentialUiState?.copy(
- currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
- activeEntry = activeEntry
- )
- )
- }
-
- fun createFlowOnDisabledProvidersSelected() {
+ fun createFlowOnLaunchSettings() {
credManRepo.onSettingLaunchCancel()
uiState = uiState.copy(dialogState = DialogState.CANCELED_FOR_SETTINGS)
}
@@ -349,16 +324,6 @@ class CredentialSelectorViewModel(
)
}
- fun createFlowOnChangeDefaultSelected() {
- uiState = uiState.copy(
- createCredentialUiState = uiState.createCredentialUiState?.copy(
- currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
- )
- )
- val providerId = uiState.createCredentialUiState?.activeEntry?.activeProvider?.id
- createFlowOnDefaultChanged(providerId)
- }
-
fun createFlowOnUseOnceSelected() {
uiState = uiState.copy(
createCredentialUiState = uiState.createCredentialUiState?.copy(
@@ -367,17 +332,6 @@ class CredentialSelectorViewModel(
)
}
- fun createFlowOnDefaultChanged(providerId: String?) {
- if (providerId != null) {
- Log.d(
- Constants.LOG_TAG, "Default provider changed to: " +
- " {provider=$providerId")
- userConfigRepo.setDefaultProvider(providerId)
- } else {
- Log.w(Constants.LOG_TAG, "Null provider is being changed")
- }
- }
-
fun createFlowOnEntrySelected(selectedEntry: BaseEntry) {
val providerId = selectedEntry.providerId
val entryKey = selectedEntry.entryKey
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 57035d426654..a35310cdad95 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -61,6 +61,7 @@ import androidx.credentials.provider.PasswordCredentialEntry
import androidx.credentials.provider.PublicKeyCredentialEntry
import androidx.credentials.provider.RemoteEntry
import org.json.JSONObject
+import java.time.Instant
// TODO: remove all !! checks
fun getAppLabel(
@@ -420,7 +421,7 @@ class CreateFlowUtils {
id = it.providerFlattenedComponentName,
displayName = providerLabel,
icon = providerIcon,
- createOptions = toCreationOptionInfoList(
+ sortedCreateOptions = toSortedCreationOptionInfoList(
it.providerFlattenedComponentName, it.saveEntries, context
),
remoteEntry = toRemoteInfo(it.providerFlattenedComponentName, it.remoteEntry),
@@ -481,8 +482,10 @@ class CreateFlowUtils {
CredentialType.PASSWORD,
appLabel,
context.getDrawable(R.drawable.ic_password_24) ?: return null,
- preferImmediatelyAvailableCredentials = false,
+ preferImmediatelyAvailableCredentials =
+ createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
+ userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
)
is CreatePublicKeyCredentialRequest -> {
newRequestDisplayInfoFromPasskeyJson(
@@ -492,6 +495,7 @@ class CreateFlowUtils {
preferImmediatelyAvailableCredentials =
createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
+ userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
)
}
is CreateCustomCredentialRequest -> {
@@ -506,8 +510,10 @@ class CreateFlowUtils {
appName = appLabel,
typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context)
?: context.getDrawable(R.drawable.ic_other_sign_in_24) ?: return null,
- preferImmediatelyAvailableCredentials = false,
+ preferImmediatelyAvailableCredentials =
+ createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
+ userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
)
}
else -> null
@@ -518,13 +524,13 @@ class CreateFlowUtils {
enabledProviders: List<EnabledProviderInfo>,
disabledProviders: List<DisabledProviderInfo>?,
defaultProviderIdPreferredByApp: String?,
- defaultProviderIdSetByUser: String?,
+ defaultProviderIdsSetByUser: Set<String>,
requestDisplayInfo: RequestDisplayInfo,
isOnPasskeyIntroStateAlready: Boolean,
isPasskeyFirstUse: Boolean,
): CreateCredentialUiState? {
- var lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo? = null
var remoteEntry: RemoteInfo? = null
+ var remoteEntryProvider: EnabledProviderInfo? = null
var defaultProviderPreferredByApp: EnabledProviderInfo? = null
var defaultProviderSetByUser: EnabledProviderInfo? = null
var createOptionsPairs:
@@ -535,14 +541,24 @@ class CreateFlowUtils {
defaultProviderPreferredByApp = enabledProvider
}
}
- if (defaultProviderIdSetByUser != null) {
- if (enabledProvider.id == defaultProviderIdSetByUser) {
+ if (enabledProvider.sortedCreateOptions.isNotEmpty() &&
+ defaultProviderIdsSetByUser.contains(enabledProvider.id)) {
+ if (defaultProviderSetByUser == null) {
defaultProviderSetByUser = enabledProvider
+ } else {
+ val newLastUsedTime = enabledProvider.sortedCreateOptions.firstOrNull()
+ ?.lastUsedTime
+ val curLastUsedTime = defaultProviderSetByUser?.sortedCreateOptions
+ ?.firstOrNull()?.lastUsedTime ?: Instant.MIN
+ if (newLastUsedTime != null) {
+ if (curLastUsedTime == null || newLastUsedTime > curLastUsedTime) {
+ defaultProviderSetByUser = enabledProvider
+ }
+ }
}
}
- if (enabledProvider.createOptions.isNotEmpty()) {
- lastSeenProviderWithNonEmptyCreateOptions = enabledProvider
- enabledProvider.createOptions.forEach {
+ if (enabledProvider.sortedCreateOptions.isNotEmpty()) {
+ enabledProvider.sortedCreateOptions.forEach {
createOptionsPairs.add(Pair(it, enabledProvider))
}
}
@@ -554,6 +570,7 @@ class CreateFlowUtils {
return null
}
remoteEntry = currRemoteEntry
+ remoteEntryProvider = enabledProvider
}
}
val defaultProvider = defaultProviderPreferredByApp ?: defaultProviderSetByUser
@@ -561,27 +578,26 @@ class CreateFlowUtils {
createOptionSize = createOptionsPairs.size,
isOnPasskeyIntroStateAlready = isOnPasskeyIntroStateAlready,
requestDisplayInfo = requestDisplayInfo,
- defaultProvider = defaultProvider,
remoteEntry = remoteEntry,
isPasskeyFirstUse = isPasskeyFirstUse
) ?: return null
+ val sortedCreateOptionsPairs = createOptionsPairs.sortedWith(
+ compareByDescending { it.first.lastUsedTime }
+ )
return CreateCredentialUiState(
enabledProviders = enabledProviders,
disabledProviders = disabledProviders,
currentScreenState = initialScreenState,
requestDisplayInfo = requestDisplayInfo,
- sortedCreateOptionsPairs = createOptionsPairs.sortedWith(
- compareByDescending { it.first.lastUsedTime }
- ),
- hasDefaultProvider = defaultProvider != null,
+ sortedCreateOptionsPairs = sortedCreateOptionsPairs,
activeEntry = toActiveEntry(
- /*defaultProvider=*/defaultProvider,
- /*createOptionSize=*/createOptionsPairs.size,
- /*lastSeenProviderWithNonEmptyCreateOptions=*/
- lastSeenProviderWithNonEmptyCreateOptions,
- /*remoteEntry=*/remoteEntry
+ defaultProvider = defaultProvider,
+ sortedCreateOptionsPairs = sortedCreateOptionsPairs,
+ remoteEntry = remoteEntry,
+ remoteEntryProvider = remoteEntryProvider,
),
remoteEntry = remoteEntry,
+ foundCandidateFromUserDefaultProvider = defaultProviderSetByUser != null,
)
}
@@ -589,59 +605,43 @@ class CreateFlowUtils {
createOptionSize: Int,
isOnPasskeyIntroStateAlready: Boolean,
requestDisplayInfo: RequestDisplayInfo,
- defaultProvider: EnabledProviderInfo?,
remoteEntry: RemoteInfo?,
isPasskeyFirstUse: Boolean,
): CreateScreenState? {
- return if (isPasskeyFirstUse && requestDisplayInfo.type ==
- CredentialType.PASSKEY && !isOnPasskeyIntroStateAlready) {
+ return if (isPasskeyFirstUse && requestDisplayInfo.type == CredentialType.PASSKEY &&
+ !isOnPasskeyIntroStateAlready) {
CreateScreenState.PASSKEY_INTRO
- } else if ((defaultProvider == null || defaultProvider.createOptions.isEmpty()) &&
- createOptionSize > 1) {
- CreateScreenState.PROVIDER_SELECTION
- } else if (((defaultProvider == null || defaultProvider.createOptions.isEmpty()) &&
- createOptionSize == 1) || (defaultProvider != null &&
- defaultProvider.createOptions.isNotEmpty())) {
- CreateScreenState.CREATION_OPTION_SELECTION
} else if (createOptionSize == 0 && remoteEntry != null) {
CreateScreenState.EXTERNAL_ONLY_SELECTION
} else {
- Log.d(
- Constants.LOG_TAG,
- "Unexpected failure: the screen state failed to instantiate" +
- " because the provider list is empty."
- )
- null
+ CreateScreenState.CREATION_OPTION_SELECTION
}
}
private fun toActiveEntry(
defaultProvider: EnabledProviderInfo?,
- createOptionSize: Int,
- lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo?,
+ sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
remoteEntry: RemoteInfo?,
+ remoteEntryProvider: EnabledProviderInfo?,
): ActiveEntry? {
return if (
- defaultProvider != null && defaultProvider.createOptions.isEmpty() &&
- remoteEntry != null
- ) {
- ActiveEntry(defaultProvider, remoteEntry)
- } else if (
- defaultProvider != null && defaultProvider.createOptions.isNotEmpty()
+ sortedCreateOptionsPairs.isEmpty() && remoteEntry != null &&
+ remoteEntryProvider != null
) {
- ActiveEntry(defaultProvider, defaultProvider.createOptions.first())
- } else if (createOptionSize == 1) {
- ActiveEntry(
- lastSeenProviderWithNonEmptyCreateOptions!!,
- lastSeenProviderWithNonEmptyCreateOptions.createOptions.first()
- )
+ ActiveEntry(remoteEntryProvider, remoteEntry)
+ } else if (defaultProvider != null &&
+ defaultProvider.sortedCreateOptions.isNotEmpty()) {
+ ActiveEntry(defaultProvider, defaultProvider.sortedCreateOptions.first())
+ } else if (sortedCreateOptionsPairs.isNotEmpty()) {
+ val (topEntry, topEntryProvider) = sortedCreateOptionsPairs.first()
+ ActiveEntry(topEntryProvider, topEntry)
} else null
}
/**
* Note: caller required handle empty list due to parsing error.
*/
- private fun toCreationOptionInfoList(
+ private fun toSortedCreationOptionInfoList(
providerId: String,
creationEntries: List<Entry>,
context: Context,
@@ -664,7 +664,9 @@ class CreateFlowUtils {
footerDescription = createEntry.description?.toString()
))
}
- return result
+ return result.sortedWith(
+ compareByDescending { it.lastUsedTime }
+ )
}
private fun toRemoteInfo(
@@ -690,6 +692,7 @@ class CreateFlowUtils {
context: Context,
preferImmediatelyAvailableCredentials: Boolean,
appPreferredDefaultProviderId: String?,
+ userSetDefaultProviderIds: Set<String>,
): RequestDisplayInfo? {
val json = JSONObject(requestJson)
var passkeyUsername = ""
@@ -711,6 +714,7 @@ class CreateFlowUtils {
context.getDrawable(R.drawable.ic_passkey_24) ?: return null,
preferImmediatelyAvailableCredentials,
appPreferredDefaultProviderId,
+ userSetDefaultProviderIds,
)
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/UserConfigRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/UserConfigRepo.kt
index a17f2c88abcd..bfcca4970a71 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/UserConfigRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/UserConfigRepo.kt
@@ -23,15 +23,6 @@ class UserConfigRepo(context: Context) {
val sharedPreferences: SharedPreferences = context.getSharedPreferences(
context.packageName, Context.MODE_PRIVATE)
- fun setDefaultProvider(
- providerId: String
- ) {
- sharedPreferences.edit().apply {
- putString(DEFAULT_PROVIDER, providerId)
- apply()
- }
- }
-
fun setIsPasskeyFirstUse(
isFirstUse: Boolean
) {
@@ -41,16 +32,11 @@ class UserConfigRepo(context: Context) {
}
}
- fun getDefaultProviderId(): String? {
- return sharedPreferences.getString(DEFAULT_PROVIDER, null)
- }
-
fun getIsPasskeyFirstUse(): Boolean {
return sharedPreferences.getBoolean(IS_PASSKEY_FIRST_USE, true)
}
companion object {
- const val DEFAULT_PROVIDER = "default_provider"
// This first use value only applies to passkeys, not related with if generally
// credential manager is first use or not
const val IS_PASSKEY_FIRST_USE = "is_passkey_first_use"
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 9d871ed75494..d16120fee452 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -88,27 +88,11 @@ fun CreateCredentialScreen(
onLearnMore = viewModel::createFlowOnLearnMore,
onLog = { viewModel.logUiEvent(it) },
)
- CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
- requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
- disabledProviderList = createCredentialUiState
- .disabledProviders,
- sortedCreateOptionsPairs =
- createCredentialUiState.sortedCreateOptionsPairs,
- hasRemoteEntry = createCredentialUiState.remoteEntry != null,
- onOptionSelected =
- viewModel::createFlowOnEntrySelectedFromFirstUseScreen,
- onDisabledProvidersSelected =
- viewModel::createFlowOnDisabledProvidersSelected,
- onMoreOptionsSelected =
- viewModel::createFlowOnMoreOptionsSelectedOnProviderSelection,
- onLog = { viewModel.logUiEvent(it) },
- )
CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
enabledProviderList = createCredentialUiState.enabledProviders,
providerInfo = createCredentialUiState
.activeEntry?.activeProvider!!,
- hasDefaultProvider = createCredentialUiState.hasDefaultProvider,
createOptionInfo =
createCredentialUiState.activeEntry.activeEntryInfo
as CreateOptionInfo,
@@ -121,21 +105,15 @@ fun CreateCredentialScreen(
CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
enabledProviderList = createCredentialUiState.enabledProviders,
- disabledProviderList = createCredentialUiState
- .disabledProviders,
+ disabledProviderList = createCredentialUiState.disabledProviders,
sortedCreateOptionsPairs =
createCredentialUiState.sortedCreateOptionsPairs,
- hasDefaultProvider = createCredentialUiState.hasDefaultProvider,
- isFromProviderSelection =
- createCredentialUiState.isFromProviderSelection!!,
- onBackProviderSelectionButtonSelected =
- viewModel::createFlowOnBackProviderSelectionButtonSelected,
onBackCreationSelectionButtonSelected =
viewModel::createFlowOnBackCreationSelectionButtonSelected,
onOptionSelected =
viewModel::createFlowOnEntrySelectedFromMoreOptionScreen,
onDisabledProvidersSelected =
- viewModel::createFlowOnDisabledProvidersSelected,
+ viewModel::createFlowOnLaunchSettings,
onRemoteEntrySelected = viewModel::createFlowOnEntrySelected,
onLog = { viewModel.logUiEvent(it) },
)
@@ -144,11 +122,11 @@ fun CreateCredentialScreen(
viewModel.onIllegalUiState("Expect active entry to be non-null" +
" upon default provider dialog.")
} else {
- DefaultProviderConfirmationCard(
+ NonDefaultUsageConfirmationCard(
selectedEntry = createCredentialUiState.activeEntry,
onIllegalScreenState = viewModel::onIllegalUiState,
- onChangeDefaultSelected =
- viewModel::createFlowOnChangeDefaultSelected,
+ onLaunchSettings =
+ viewModel::createFlowOnLaunchSettings,
onUseOnceSelected = viewModel::createFlowOnUseOnceSelected,
onLog = { viewModel.logUiEvent(it) },
)
@@ -263,94 +241,11 @@ fun PasskeyIntroCard(
}
@Composable
-fun ProviderSelectionCard(
- requestDisplayInfo: RequestDisplayInfo,
- disabledProviderList: List<DisabledProviderInfo>?,
- sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
- hasRemoteEntry: Boolean,
- onOptionSelected: (ActiveEntry) -> Unit,
- onDisabledProvidersSelected: () -> Unit,
- onMoreOptionsSelected: () -> Unit,
- onLog: @Composable (UiEventEnum) -> Unit,
-) {
- SheetContainerCard {
- item { HeadlineIcon(bitmap = requestDisplayInfo.typeIcon.toBitmap().asImageBitmap()) }
- item { Divider(thickness = 16.dp, color = Color.Transparent) }
- item {
- HeadlineText(
- text = stringResource(
- R.string.choose_provider_title,
- when (requestDisplayInfo.type) {
- CredentialType.PASSKEY ->
- stringResource(R.string.passkeys)
- CredentialType.PASSWORD ->
- stringResource(R.string.passwords)
- CredentialType.UNKNOWN -> stringResource(R.string.sign_in_info)
- }
- )
- )
- }
- item { Divider(thickness = 24.dp, color = Color.Transparent) }
-
- item {
- Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) {
- BodyMediumText(text = stringResource(R.string.choose_provider_body))
- }
- }
- item { Divider(thickness = 16.dp, color = Color.Transparent) }
- item {
- CredentialContainerCard {
- Column(
- verticalArrangement = Arrangement.spacedBy(2.dp)
- ) {
- sortedCreateOptionsPairs.forEach { entry ->
- MoreOptionsInfoRow(
- requestDisplayInfo = requestDisplayInfo,
- providerInfo = entry.second,
- createOptionInfo = entry.first,
- onOptionSelected = {
- onOptionSelected(
- ActiveEntry(
- entry.second,
- entry.first
- )
- )
- }
- )
- }
- MoreOptionsDisabledProvidersRow(
- disabledProviders = disabledProviderList,
- onDisabledProvidersSelected = onDisabledProvidersSelected,
- )
- }
- }
- }
- if (hasRemoteEntry) {
- item { Divider(thickness = 24.dp, color = Color.Transparent) }
- item {
- CtaButtonRow(
- leftButton = {
- ActionButton(
- stringResource(R.string.string_more_options),
- onMoreOptionsSelected
- )
- }
- )
- }
- }
- }
- onLog(CreateCredentialEvent.CREDMAN_CREATE_CRED_PROVIDER_SELECTION)
-}
-
-@Composable
fun MoreOptionsSelectionCard(
requestDisplayInfo: RequestDisplayInfo,
enabledProviderList: List<EnabledProviderInfo>,
disabledProviderList: List<DisabledProviderInfo>?,
sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
- hasDefaultProvider: Boolean,
- isFromProviderSelection: Boolean,
- onBackProviderSelectionButtonSelected: () -> Unit,
onBackCreationSelectionButtonSelected: () -> Unit,
onOptionSelected: (ActiveEntry) -> Unit,
onDisabledProvidersSelected: () -> Unit,
@@ -369,9 +264,7 @@ fun MoreOptionsSelectionCard(
CredentialType.UNKNOWN -> stringResource(R.string.sign_in_info)
}
),
- onNavigationIconClicked =
- if (isFromProviderSelection) onBackProviderSelectionButtonSelected
- else onBackCreationSelectionButtonSelected,
+ onNavigationIconClicked = onBackCreationSelectionButtonSelected,
bottomPadding = 16.dp,
)
}) {
@@ -379,30 +272,26 @@ fun MoreOptionsSelectionCard(
item {
CredentialContainerCard {
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
- // Only in the flows with default provider(not first time use) we can show the
- // createOptions here, or they will be shown on ProviderSelectionCard
- if (hasDefaultProvider) {
- sortedCreateOptionsPairs.forEach { entry ->
- MoreOptionsInfoRow(
- requestDisplayInfo = requestDisplayInfo,
- providerInfo = entry.second,
- createOptionInfo = entry.first,
- onOptionSelected = {
- onOptionSelected(
- ActiveEntry(
- entry.second,
- entry.first
- )
+ sortedCreateOptionsPairs.forEach { entry ->
+ MoreOptionsInfoRow(
+ requestDisplayInfo = requestDisplayInfo,
+ providerInfo = entry.second,
+ createOptionInfo = entry.first,
+ onOptionSelected = {
+ onOptionSelected(
+ ActiveEntry(
+ entry.second,
+ entry.first
)
- }
- )
- }
- MoreOptionsDisabledProvidersRow(
- disabledProviders = disabledProviderList,
- onDisabledProvidersSelected =
- onDisabledProvidersSelected,
+ )
+ }
)
}
+ MoreOptionsDisabledProvidersRow(
+ disabledProviders = disabledProviderList,
+ onDisabledProvidersSelected =
+ onDisabledProvidersSelected,
+ )
enabledProviderList.forEach {
if (it.remoteEntry != null) {
RemoteEntryRow(
@@ -420,10 +309,10 @@ fun MoreOptionsSelectionCard(
}
@Composable
-fun DefaultProviderConfirmationCard(
+fun NonDefaultUsageConfirmationCard(
selectedEntry: ActiveEntry,
onIllegalScreenState: (String) -> Unit,
- onChangeDefaultSelected: () -> Unit,
+ onLaunchSettings: () -> Unit,
onUseOnceSelected: () -> Unit,
onLog: @Composable (UiEventEnum) -> Unit,
) {
@@ -454,14 +343,14 @@ fun DefaultProviderConfirmationCard(
CtaButtonRow(
leftButton = {
ActionButton(
- stringResource(R.string.use_once),
- onClick = onUseOnceSelected
+ stringResource(R.string.settings),
+ onClick = onLaunchSettings,
)
},
rightButton = {
ConfirmButton(
- stringResource(R.string.set_as_default),
- onClick = onChangeDefaultSelected
+ stringResource(R.string.use_once),
+ onClick = onUseOnceSelected,
)
},
)
@@ -479,7 +368,6 @@ fun CreationSelectionCard(
onOptionSelected: (BaseEntry) -> Unit,
onConfirm: () -> Unit,
onMoreOptionsSelected: () -> Unit,
- hasDefaultProvider: Boolean,
onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard {
@@ -527,16 +415,9 @@ fun CreationSelectionCard(
if (enabledProvider.remoteEntry != null) {
remoteEntry = enabledProvider.remoteEntry
}
- createOptionsSize += enabledProvider.createOptions.size
- }
- val shouldShowMoreOptionsButton = if (!hasDefaultProvider) {
- // User has already been presented with all options on the default provider
- // selection screen. Don't show them again. Therefore, only show the more option
- // button if remote option is present.
- remoteEntry != null
- } else {
- createOptionsSize > 1 || remoteEntry != null
+ createOptionsSize += enabledProvider.sortedCreateOptions.size
}
+ val shouldShowMoreOptionsButton = createOptionsSize > 1 || remoteEntry != null
item {
CtaButtonRow(
leftButton = if (shouldShowMoreOptionsButton) {
@@ -584,7 +465,17 @@ fun ExternalOnlySelectionCard(
SheetContainerCard {
item { HeadlineIcon(imageVector = Icons.Outlined.QrCodeScanner) }
item { Divider(thickness = 16.dp, color = Color.Transparent) }
- item { HeadlineText(text = stringResource(R.string.create_passkey_in_other_device_title)) }
+ item {
+ HeadlineText(
+ text = stringResource(
+ when (requestDisplayInfo.type) {
+ CredentialType.PASSKEY -> R.string.create_passkey_in_other_device_title
+ CredentialType.PASSWORD -> R.string.save_password_on_other_device_title
+ else -> R.string.save_sign_in_on_other_device_title
+ }
+ )
+ )
+ }
item { Divider(thickness = 24.dp, color = Color.Transparent) }
item {
CredentialContainerCard {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 225dbf2b744f..fe1ce1b60413 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -29,12 +29,9 @@ data class CreateCredentialUiState(
val currentScreenState: CreateScreenState,
val requestDisplayInfo: RequestDisplayInfo,
val sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
- // Should not change with the real time update of default provider, only determine whether
- // we're showing provider selection page at the beginning
- val hasDefaultProvider: Boolean,
val activeEntry: ActiveEntry? = null,
val remoteEntry: RemoteInfo? = null,
- val isFromProviderSelection: Boolean? = null,
+ val foundCandidateFromUserDefaultProvider: Boolean,
)
internal fun hasContentToDisplay(state: CreateCredentialUiState): Boolean {
@@ -50,11 +47,12 @@ open class ProviderInfo(
)
class EnabledProviderInfo(
- icon: Drawable,
- id: String,
- displayName: String,
- var createOptions: List<CreateOptionInfo>,
- var remoteEntry: RemoteInfo?,
+ icon: Drawable,
+ id: String,
+ displayName: String,
+ // Sorted by last used time
+ var sortedCreateOptions: List<CreateOptionInfo>,
+ var remoteEntry: RemoteInfo?,
) : ProviderInfo(icon, id, displayName)
class DisabledProviderInfo(
@@ -108,6 +106,7 @@ data class RequestDisplayInfo(
val typeIcon: Drawable,
val preferImmediatelyAvailableCredentials: Boolean,
val appPreferredDefaultProviderId: String?,
+ val userSetDefaultProviderIds: Set<String>,
)
/**
@@ -123,7 +122,6 @@ data class ActiveEntry (
enum class CreateScreenState {
PASSKEY_INTRO,
MORE_ABOUT_PASSKEYS_INTRO,
- PROVIDER_SELECTION,
CREATION_OPTION_SELECTION,
MORE_OPTIONS_SELECTION,
DEFAULT_PROVIDER_CONFIRMATION,
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java b/packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java
index 4c5875b1f2d9..7b17cbdd3a1e 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java
@@ -16,14 +16,14 @@
package com.android.packageinstaller;
+import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_STAGED_SESSION_ID;
+
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.Nullable;
-import java.io.File;
-
/**
* Trampoline activity. Calls PackageInstallerActivity and deletes staged install file onResult.
*/
@@ -52,8 +52,13 @@ public class DeleteStagedFileOnResult extends Activity {
super.onDestroy();
if (isFinishing()) {
- File sourceFile = new File(getIntent().getData().getPath());
- new Thread(sourceFile::delete).start();
+ // While we expect PIA/InstallStaging to abandon/commit the session, still there
+ // might be cases when the session becomes orphan.
+ int sessionId = getIntent().getIntExtra(EXTRA_STAGED_SESSION_ID, 0);
+ try {
+ getPackageManager().getPackageInstaller().abandonSession(sessionId);
+ } catch (SecurityException ignored) {
+ }
}
}
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index c6217ece800d..7bea33971259 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -16,17 +16,17 @@
package com.android.packageinstaller;
+import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_STAGED_SESSION_ID;
+
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInstaller;
-import android.content.pm.PackageInstaller.InstallInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Process;
import android.util.Log;
import android.view.View;
import android.widget.Button;
@@ -34,10 +34,7 @@ import android.widget.Button;
import androidx.annotation.Nullable;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
/**
* Send package to the package manager and handle results from package manager. Once the
@@ -77,7 +74,7 @@ public class InstallInstalling extends AlertActivity {
.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI = getIntent().getData();
- if ("package".equals(mPackageURI.getScheme())) {
+ if (PackageInstallerActivity.SCHEME_PACKAGE.equals(mPackageURI.getScheme())) {
try {
getPackageManager().installExistingPackage(appInfo.packageName);
launchSuccess();
@@ -86,6 +83,8 @@ public class InstallInstalling extends AlertActivity {
PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
} else {
+ // ContentResolver.SCHEME_FILE
+ // STAGED_SESSION_ID extra contains an ID of a previously staged install session.
final File sourceFile = new File(mPackageURI.getPath());
PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
@@ -122,41 +121,6 @@ public class InstallInstalling extends AlertActivity {
// Does not happen
}
} else {
- PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- final Uri referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER);
- params.setPackageSource(
- referrerUri != null ? PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE
- : PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE);
- params.setInstallAsInstantApp(false);
- params.setReferrerUri(referrerUri);
- params.setOriginatingUri(getIntent()
- .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
- params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
- Process.INVALID_UID));
- params.setInstallerPackageName(getIntent().getStringExtra(
- Intent.EXTRA_INSTALLER_PACKAGE_NAME));
- params.setInstallReason(PackageManager.INSTALL_REASON_USER);
-
- File file = new File(mPackageURI.getPath());
- try {
- final InstallInfo result = getPackageManager().getPackageInstaller()
- .readInstallInfo(file, 0);
- params.setAppPackageName(result.getPackageName());
- params.setInstallLocation(result.getInstallLocation());
- try {
- params.setSize(result.calculateInstalledSize(params));
- } catch (IOException e) {
- e.printStackTrace();
- params.setSize(file.length());
- }
- } catch (PackageInstaller.PackageParsingException e) {
-
- Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.", e);
- Log.e(LOG_TAG,
- "Cannot calculate installed size " + file + ". Try only apk size.");
- params.setSize(file.length());
- }
try {
mInstallId = InstallEventReceiver
.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
@@ -166,9 +130,14 @@ public class InstallInstalling extends AlertActivity {
PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
- try {
- mSessionId = getPackageManager().getPackageInstaller().createSession(params);
- } catch (IOException e) {
+ mSessionId = getIntent().getIntExtra(EXTRA_STAGED_SESSION_ID, 0);
+ // Try to open session previously staged in InstallStaging.
+ try (PackageInstaller.Session ignored =
+ getPackageManager().getPackageInstaller().openSession(
+ mSessionId)) {
+ Log.d(LOG_TAG, "Staged session is valid, proceeding with the install");
+ } catch (IOException | SecurityException e) {
+ Log.e(LOG_TAG, "Invalid session id passed", e);
launchFailure(PackageInstaller.STATUS_FAILURE,
PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
@@ -293,57 +262,9 @@ public class InstallInstalling extends AlertActivity {
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
- PackageInstaller.Session session;
try {
- session = getPackageManager().getPackageInstaller().openSession(mSessionId);
+ return getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
- synchronized (this) {
- isDone = true;
- notifyAll();
- }
- return null;
- }
-
- session.setStagingProgress(0);
-
- try {
- File file = new File(mPackageURI.getPath());
-
- try (InputStream in = new FileInputStream(file)) {
- long sizeBytes = file.length();
- long totalRead = 0;
- try (OutputStream out = session
- .openWrite("PackageInstaller", 0, sizeBytes)) {
- byte[] buffer = new byte[1024 * 1024];
- while (true) {
- int numRead = in.read(buffer);
-
- if (numRead == -1) {
- session.fsync(out);
- break;
- }
-
- if (isCancelled()) {
- session.close();
- break;
- }
-
- out.write(buffer, 0, numRead);
- if (sizeBytes > 0) {
- totalRead += numRead;
- float fraction = ((float) totalRead / (float) sizeBytes);
- session.setStagingProgress(fraction);
- }
- }
- }
- }
-
- return session;
- } catch (IOException | SecurityException e) {
- Log.e(LOG_TAG, "Could not write package", e);
-
- session.close();
-
return null;
} finally {
synchronized (this) {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java
index 68de2f67bd94..097e47f58db1 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java
@@ -16,6 +16,10 @@
package com.android.packageinstaller;
+import static android.content.res.AssetFileDescriptor.UNKNOWN_LENGTH;
+
+import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_STAGED_SESSION_ID;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -23,40 +27,49 @@ import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.util.Log;
import android.view.View;
+import android.widget.ProgressBar;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
- * If a package gets installed from an content URI this step loads the package and turns it into
- * and installation from a file. Then it re-starts the installation as usual.
+ * If a package gets installed from a content URI this step stages the installation session
+ * reading bytes from the URI.
*/
public class InstallStaging extends AlertActivity {
private static final String LOG_TAG = InstallStaging.class.getSimpleName();
- private static final String STAGED_FILE = "STAGED_FILE";
+ private static final String STAGED_SESSION_ID = "STAGED_SESSION_ID";
+
+ private @Nullable PackageInstaller mInstaller;
/** Currently running task that loads the file from the content URI into a file */
private @Nullable StagingAsyncTask mStagingTask;
- /** The file the package is in */
- private @Nullable File mStagedFile;
+ /** The session the package is in */
+ private int mStagedSessionId;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mInstaller = getPackageManager().getPackageInstaller();
+
setFinishOnTouchOutside(true);
mAlert.setIcon(R.drawable.ic_file_download);
mAlert.setTitle(getString(R.string.app_name_unknown));
@@ -66,6 +79,9 @@ public class InstallStaging extends AlertActivity {
if (mStagingTask != null) {
mStagingTask.cancel(true);
}
+
+ cleanupStagingSession();
+
setResult(RESULT_CANCELED);
finish();
}, null);
@@ -73,11 +89,7 @@ public class InstallStaging extends AlertActivity {
requireViewById(R.id.staging).setVisibility(View.VISIBLE);
if (savedInstanceState != null) {
- mStagedFile = new File(savedInstanceState.getString(STAGED_FILE));
-
- if (!mStagedFile.exists()) {
- mStagedFile = null;
- }
+ mStagedSessionId = savedInstanceState.getInt(STAGED_SESSION_ID, 0);
}
}
@@ -85,21 +97,41 @@ public class InstallStaging extends AlertActivity {
protected void onResume() {
super.onResume();
- // This is the first onResume in a single life of the activity
+ // This is the first onResume in a single life of the activity.
if (mStagingTask == null) {
- // File does not exist, or became invalid
- if (mStagedFile == null) {
- // Create file delayed to be able to show error
+ if (mStagedSessionId > 0) {
+ final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(
+ mStagedSessionId);
+ if (info == null || !info.isActive() || info.getResolvedBaseApkPath() == null) {
+ Log.w(LOG_TAG, "Session " + mStagedSessionId + " in funky state; ignoring");
+ if (info != null) {
+ cleanupStagingSession();
+ }
+ mStagedSessionId = 0;
+ }
+ }
+
+ // Session does not exist, or became invalid.
+ if (mStagedSessionId <= 0) {
+ // Create session here to be able to show error.
+ final Uri packageUri = getIntent().getData();
+ final AssetFileDescriptor afd = openAssetFileDescriptor(packageUri);
try {
- mStagedFile = TemporaryFileManager.getStagedFile(this);
+ ParcelFileDescriptor pfd = afd != null ? afd.getParcelFileDescriptor() : null;
+ PackageInstaller.SessionParams params = createSessionParams(
+ mInstaller, getIntent(), pfd, packageUri.toString());
+ mStagedSessionId = mInstaller.createSession(params);
} catch (IOException e) {
+ Log.w(LOG_TAG, "Failed to create a staging session", e);
showError();
return;
+ } finally {
+ PackageUtil.safeClose(afd);
}
}
mStagingTask = new StagingAsyncTask();
- mStagingTask.execute(getIntent().getData());
+ mStagingTask.execute();
}
}
@@ -107,7 +139,7 @@ public class InstallStaging extends AlertActivity {
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putString(STAGED_FILE, mStagedFile.getPath());
+ outState.putInt(STAGED_SESSION_ID, mStagedSessionId);
}
@Override
@@ -119,6 +151,65 @@ public class InstallStaging extends AlertActivity {
super.onDestroy();
}
+ private AssetFileDescriptor openAssetFileDescriptor(Uri uri) {
+ try {
+ return getContentResolver().openAssetFileDescriptor(uri, "r");
+ } catch (Exception e) {
+ Log.w(LOG_TAG, "Failed to open asset file descriptor", e);
+ return null;
+ }
+ }
+
+ private static PackageInstaller.SessionParams createSessionParams(
+ @NonNull PackageInstaller installer, @NonNull Intent intent,
+ @Nullable ParcelFileDescriptor pfd, @NonNull String debugPathName) {
+ PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ final Uri referrerUri = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+ params.setPackageSource(
+ referrerUri != null ? PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE
+ : PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE);
+ params.setInstallAsInstantApp(false);
+ params.setReferrerUri(referrerUri);
+ params.setOriginatingUri(intent
+ .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
+ params.setOriginatingUid(intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
+ Process.INVALID_UID));
+ params.setInstallerPackageName(intent.getStringExtra(
+ Intent.EXTRA_INSTALLER_PACKAGE_NAME));
+ params.setInstallReason(PackageManager.INSTALL_REASON_USER);
+
+ if (pfd != null) {
+ try {
+ final PackageInstaller.InstallInfo result = installer.readInstallInfo(pfd,
+ debugPathName, 0);
+ params.setAppPackageName(result.getPackageName());
+ params.setInstallLocation(result.getInstallLocation());
+ params.setSize(result.calculateInstalledSize(params, pfd));
+ } catch (PackageInstaller.PackageParsingException | IOException e) {
+ Log.e(LOG_TAG, "Cannot parse package " + debugPathName + ". Assuming defaults.", e);
+ Log.e(LOG_TAG,
+ "Cannot calculate installed size " + debugPathName
+ + ". Try only apk size.");
+ params.setSize(pfd.getStatSize());
+ }
+ } else {
+ Log.e(LOG_TAG, "Cannot parse package " + debugPathName + ". Assuming defaults.");
+ }
+ return params;
+ }
+
+ private void cleanupStagingSession() {
+ if (mStagedSessionId > 0) {
+ try {
+ mInstaller.abandonSession(mStagedSessionId);
+ } catch (SecurityException ignored) {
+
+ }
+ mStagedSessionId = 0;
+ }
+ }
+
/**
* Show an error message and set result as error.
*/
@@ -165,58 +256,109 @@ public class InstallStaging extends AlertActivity {
}
}
- private final class StagingAsyncTask extends AsyncTask<Uri, Void, Boolean> {
+ private final class StagingAsyncTask extends
+ AsyncTask<Void, Integer, PackageInstaller.SessionInfo> {
+ private ProgressBar mProgressBar = null;
+
+ private long getContentSizeBytes() {
+ try (AssetFileDescriptor afd = openAssetFileDescriptor(getIntent().getData())) {
+ return afd != null ? afd.getLength() : UNKNOWN_LENGTH;
+ } catch (IOException ignored) {
+ return UNKNOWN_LENGTH;
+ }
+ }
+
@Override
- protected Boolean doInBackground(Uri... params) {
- if (params == null || params.length <= 0) {
- return false;
+ protected void onPreExecute() {
+ final long sizeBytes = getContentSizeBytes();
+
+ mProgressBar = sizeBytes > 0 ? requireViewById(R.id.progress_indeterminate) : null;
+ if (mProgressBar != null) {
+ mProgressBar.setProgress(0);
+ mProgressBar.setMax(100);
+ mProgressBar.setIndeterminate(false);
}
- Uri packageUri = params[0];
- try (InputStream in = getContentResolver().openInputStream(packageUri)) {
- // Despite the comments in ContentResolver#openInputStream the returned stream can
- // be null.
+ }
+
+ @Override
+ protected PackageInstaller.SessionInfo doInBackground(Void... params) {
+ Uri packageUri = getIntent().getData();
+ try (PackageInstaller.Session session = mInstaller.openSession(mStagedSessionId);
+ InputStream in = getContentResolver().openInputStream(packageUri)) {
+ session.setStagingProgress(0);
+
if (in == null) {
- return false;
+ return null;
}
- try (OutputStream out = new FileOutputStream(mStagedFile)) {
+ long sizeBytes = getContentSizeBytes();
+
+ long totalRead = 0;
+ try (OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes)) {
byte[] buffer = new byte[1024 * 1024];
- int bytesRead;
- while ((bytesRead = in.read(buffer)) >= 0) {
- // Be nice and respond to a cancellation
+ while (true) {
+ int numRead = in.read(buffer);
+
+ if (numRead == -1) {
+ session.fsync(out);
+ break;
+ }
+
if (isCancelled()) {
- return false;
+ break;
+ }
+
+ out.write(buffer, 0, numRead);
+ if (sizeBytes > 0) {
+ totalRead += numRead;
+ float fraction = ((float) totalRead / (float) sizeBytes);
+ session.setStagingProgress(fraction);
+ publishProgress((int) (fraction * 100.0));
}
- out.write(buffer, 0, bytesRead);
}
}
+
+ return mInstaller.getSessionInfo(mStagedSessionId);
} catch (IOException | SecurityException | IllegalStateException
- | IllegalArgumentException e) {
+ | IllegalArgumentException e) {
Log.w(LOG_TAG, "Error staging apk from content URI", e);
- return false;
+ return null;
}
- return true;
}
@Override
- protected void onPostExecute(Boolean success) {
- if (success) {
- // Now start the installation again from a file
- Intent installIntent = new Intent(getIntent());
- installIntent.setClass(InstallStaging.this, DeleteStagedFileOnResult.class);
- installIntent.setData(Uri.fromFile(mStagedFile));
-
- if (installIntent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
- installIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
- }
-
- installIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
- startActivity(installIntent);
+ protected void onProgressUpdate(Integer... progress) {
+ if (mProgressBar != null && progress != null && progress.length > 0) {
+ mProgressBar.setProgress(progress[0], true);
+ }
+ }
- InstallStaging.this.finish();
- } else {
+ @Override
+ protected void onPostExecute(PackageInstaller.SessionInfo sessionInfo) {
+ if (sessionInfo == null || !sessionInfo.isActive()
+ || sessionInfo.getResolvedBaseApkPath() == null) {
+ Log.w(LOG_TAG, "Session info is invalid: " + sessionInfo);
+ cleanupStagingSession();
showError();
+ return;
+ }
+
+ // Pass the staged session to the installer.
+ Intent installIntent = new Intent(getIntent());
+ installIntent.setClass(InstallStaging.this, DeleteStagedFileOnResult.class);
+ installIntent.setData(Uri.fromFile(new File(sessionInfo.getResolvedBaseApkPath())));
+
+ installIntent.putExtra(EXTRA_STAGED_SESSION_ID, mStagedSessionId);
+
+ if (installIntent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
+ installIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
}
+
+ installIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+
+ startActivity(installIntent);
+
+ InstallStaging.this.finish();
}
}
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index ac32020e842a..3f98867cb267 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -77,7 +77,21 @@ public class InstallStart extends Activity {
}
final ApplicationInfo sourceInfo = getSourceInfo(callingPackage);
- final int originatingUid = getOriginatingUid(sourceInfo);
+ // Uid of the source package, coming from ActivityManager
+ int callingUid = getLaunchedFromUid();
+ if (callingUid == Process.INVALID_UID) {
+ // Cannot reach ActivityManager. Aborting install.
+ Log.e(LOG_TAG, "Could not determine the launching uid.");
+ }
+ // Uid of the source package, with a preference to uid from ApplicationInfo
+ final int originatingUid = sourceInfo != null ? sourceInfo.uid : callingUid;
+
+ if (callingUid == Process.INVALID_UID && sourceInfo == null) {
+ mAbortInstall = true;
+ }
+
+ boolean isDocumentsManager = checkPermission(Manifest.permission.MANAGE_DOCUMENTS,
+ -1, callingUid) == PackageManager.PERMISSION_GRANTED;
boolean isTrustedSource = false;
if (sourceInfo != null && sourceInfo.isPrivilegedApp()) {
isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false) || (
@@ -86,7 +100,8 @@ public class InstallStart extends Activity {
== PackageManager.PERMISSION_GRANTED);
}
- if (!isTrustedSource && originatingUid != Process.INVALID_UID) {
+ if (!isTrustedSource && !isSystemDownloadsProvider(callingUid) && !isDocumentsManager
+ && originatingUid != Process.INVALID_UID) {
final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, originatingUid);
if (targetSdkVersion < 0) {
Log.w(LOG_TAG, "Cannot get target sdk version for uid " + originatingUid);
@@ -144,14 +159,15 @@ public class InstallStart extends Activity {
if (packageUri != null
&& packageUri.getScheme().equals(ContentResolver.SCHEME_CONTENT)
- && canPackageQuery(originatingUid, packageUri)) {
+ && canPackageQuery(callingUid, packageUri)) {
// [IMPORTANT] This path is deprecated, but should still work. Only necessary
// features should be added.
- // Copy file to prevent it from being changed underneath this process
+ // Stage a session with this file to prevent it from being changed underneath
+ // this process.
nextActivity.setClass(this, InstallStaging.class);
- } else if (packageUri != null && packageUri.getScheme().equals(
- PackageInstallerActivity.SCHEME_PACKAGE)) {
+ } else if (packageUri != null && PackageInstallerActivity.SCHEME_PACKAGE.equals(
+ packageUri.getScheme())) {
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Intent result = new Intent();
@@ -212,41 +228,6 @@ public class InstallStart extends Activity {
return null;
}
- /**
- * Get the originating uid if possible, or {@link Process#INVALID_UID} if not available
- *
- * @param sourceInfo The source of this installation
- * @return The UID of the installation source or INVALID_UID
- */
- private int getOriginatingUid(@Nullable ApplicationInfo sourceInfo) {
- // The originating uid from the intent. We only trust/use this if it comes from either
- // the document manager app or the downloads provider
- final int uidFromIntent = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
- Process.INVALID_UID);
-
- final int callingUid;
- if (sourceInfo != null) {
- callingUid = sourceInfo.uid;
- } else {
- callingUid = getLaunchedFromUid();
- if (callingUid == Process.INVALID_UID) {
- // Cannot reach ActivityManager. Aborting install.
- Log.e(LOG_TAG, "Could not determine the launching uid.");
- mAbortInstall = true;
- return Process.INVALID_UID;
- }
- }
- if (checkPermission(Manifest.permission.MANAGE_DOCUMENTS, -1, callingUid)
- == PackageManager.PERMISSION_GRANTED) {
- return uidFromIntent;
- }
- if (isSystemDownloadsProvider(callingUid)) {
- return uidFromIntent;
- }
- // We don't trust uid from the intent. Use the calling uid instead.
- return callingUid;
- }
-
private boolean isSystemDownloadsProvider(int uid) {
final ProviderInfo downloadProviderPackage = getPackageManager().resolveContentProvider(
DOWNLOADS_AUTHORITY, 0);
@@ -260,8 +241,7 @@ public class InstallStart extends Activity {
}
@NonNull
- private boolean canPackageQuery(int originatingUid, Uri packageUri) {
- String callingPackage = mPackageManager.getPackagesForUid(originatingUid)[0];
+ private boolean canPackageQuery(int callingUid, Uri packageUri) {
ProviderInfo info = mPackageManager.resolveContentProvider(packageUri.getAuthority(),
PackageManager.ComponentInfoFlags.of(0));
if (info == null) {
@@ -269,11 +249,20 @@ public class InstallStart extends Activity {
}
String targetPackage = info.packageName;
- try {
- return mPackageManager.canPackageQuery(callingPackage, targetPackage);
- } catch (PackageManager.NameNotFoundException e) {
+ String[] callingPackages = mPackageManager.getPackagesForUid(callingUid);
+ if (callingPackages == null) {
return false;
}
+ for (String callingPackage: callingPackages) {
+ try {
+ if (mPackageManager.canPackageQuery(callingPackage, targetPackage)) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // no-op
+ }
+ }
+ return false;
}
private boolean isCallerSessionOwner(int originatingUid, int sessionId) {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 3ba2acb113d3..7e294eee024f 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -82,6 +82,7 @@ public class PackageInstallerActivity extends AlertActivity {
static final String EXTRA_CALLING_PACKAGE = "EXTRA_CALLING_PACKAGE";
static final String EXTRA_CALLING_ATTRIBUTION_TAG = "EXTRA_CALLING_ATTRIBUTION_TAG";
static final String EXTRA_ORIGINAL_SOURCE_INFO = "EXTRA_ORIGINAL_SOURCE_INFO";
+ static final String EXTRA_STAGED_SESSION_ID = "EXTRA_STAGED_SESSION_ID";
private static final String ALLOW_UNKNOWN_SOURCES_KEY =
PackageInstallerActivity.class.getName() + "ALLOW_UNKNOWN_SOURCES_KEY";
@@ -403,6 +404,10 @@ public class PackageInstallerActivity extends AlertActivity {
mReferrerURI = null;
mPendingUserActionReason = info.getPendingUserActionReason();
} else {
+ // Two possible callers:
+ // 1. InstallStart with "SCHEME_PACKAGE".
+ // 2. InstallStaging with "SCHEME_FILE" and EXTRA_STAGED_SESSION_ID with staged
+ // session id.
mSessionId = -1;
packageSource = intent.getData();
mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
@@ -721,14 +726,16 @@ public class PackageInstallerActivity extends AlertActivity {
}
private void startInstall() {
+ String installerPackageName = getIntent().getStringExtra(
+ Intent.EXTRA_INSTALLER_PACKAGE_NAME);
+ int stagedSessionId = getIntent().getIntExtra(EXTRA_STAGED_SESSION_ID, 0);
+
// Start subactivity to actually install the application
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallInstalling.class);
- String installerPackageName = getIntent().getStringExtra(
- Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
@@ -745,6 +752,9 @@ public class PackageInstallerActivity extends AlertActivity {
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
}
+ if (stagedSessionId > 0) {
+ newIntent.putExtra(EXTRA_STAGED_SESSION_ID, stagedSessionId);
+ }
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
if (mLocalLOGV) Log.i(TAG, "downloaded app uri=" + mPackageURI);
startActivity(newIntent);
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
index 698159f24bb7..0270591acceb 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
@@ -33,7 +33,9 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import java.io.Closeable;
import java.io.File;
+import java.io.IOException;
/**
* This is a utility class for defining some utility methods and constants
@@ -190,4 +192,19 @@ public class PackageUtil {
}
return targetSdkVersion;
}
+
+
+ /**
+ * Quietly close a closeable resource (e.g. a stream or file). The input may already
+ * be closed and it may even be null.
+ */
+ static void safeClose(Closeable resource) {
+ if (resource != null) {
+ try {
+ resource.close();
+ } catch (IOException ioe) {
+ // Catch and discard the error
+ }
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index c9e831256cf4..6cf6825e61e0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -50,6 +50,7 @@ import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.DoNotInline;
+import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import com.android.internal.annotations.VisibleForTesting;
@@ -638,6 +639,11 @@ public class InfoMediaManager extends MediaManager {
}
@Override
+ public void onSessionReleased(@NonNull RoutingSessionInfo session) {
+ refreshDevices();
+ }
+
+ @Override
public void onRouteListingPreferenceUpdated(
String packageName,
RouteListingPreference routeListingPreference) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 270fda89c212..096932706c88 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -141,6 +141,56 @@ public class InfoMediaManagerTest {
}
@Test
+ public void onSessionReleased_shouldUpdateConnectedDevice() {
+ final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+ final RoutingSessionInfo sessionInfo1 = mock(RoutingSessionInfo.class);
+ routingSessionInfos.add(sessionInfo1);
+ final RoutingSessionInfo sessionInfo2 = mock(RoutingSessionInfo.class);
+ routingSessionInfos.add(sessionInfo2);
+
+ final List<String> selectedRoutesSession1 = new ArrayList<>();
+ selectedRoutesSession1.add(TEST_ID_1);
+ when(sessionInfo1.getSelectedRoutes()).thenReturn(selectedRoutesSession1);
+
+ final List<String> selectedRoutesSession2 = new ArrayList<>();
+ selectedRoutesSession2.add(TEST_ID_2);
+ when(sessionInfo2.getSelectedRoutes()).thenReturn(selectedRoutesSession2);
+
+ mShadowRouter2Manager.setRoutingSessions(routingSessionInfos);
+
+ final MediaRoute2Info info1 = mock(MediaRoute2Info.class);
+ when(info1.getId()).thenReturn(TEST_ID_1);
+ when(info1.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+ final MediaRoute2Info info2 = mock(MediaRoute2Info.class);
+ when(info2.getId()).thenReturn(TEST_ID_2);
+ when(info2.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+ final List<MediaRoute2Info> routes = new ArrayList<>();
+ routes.add(info1);
+ routes.add(info2);
+ mShadowRouter2Manager.setAllRoutes(routes);
+ mShadowRouter2Manager.setTransferableRoutes(routes);
+
+ final MediaDevice mediaDevice1 = mInfoMediaManager.findMediaDevice(TEST_ID_1);
+ assertThat(mediaDevice1).isNull();
+ final MediaDevice mediaDevice2 = mInfoMediaManager.findMediaDevice(TEST_ID_2);
+ assertThat(mediaDevice2).isNull();
+
+ mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
+ final MediaDevice infoDevice1 = mInfoMediaManager.mMediaDevices.get(0);
+ assertThat(infoDevice1.getId()).isEqualTo(TEST_ID_1);
+ final MediaDevice infoDevice2 = mInfoMediaManager.mMediaDevices.get(1);
+ assertThat(infoDevice2.getId()).isEqualTo(TEST_ID_2);
+ // The active routing session is the last one in the list, which maps to infoDevice2.
+ assertThat(mInfoMediaManager.getCurrentConnectedDevice()).isEqualTo(infoDevice2);
+
+ routingSessionInfos.remove(sessionInfo2);
+ mInfoMediaManager.mMediaRouterCallback.onSessionReleased(sessionInfo2);
+ assertThat(mInfoMediaManager.getCurrentConnectedDevice()).isEqualTo(infoDevice1);
+ }
+
+ @Test
public void onRouteAdded_buildAllRoutes_shouldAddMediaDevice() {
final MediaRoute2Info info = mock(MediaRoute2Info.class);
when(info.getId()).thenReturn(TEST_ID);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 706666cbebab..2e49dd5eeba9 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -841,7 +841,8 @@ public class SettingsBackupTest {
Settings.Secure.ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
Settings.Secure.UI_TRANSLATION_ENABLED,
- Settings.Secure.CREDENTIAL_SERVICE);
+ Settings.Secure.CREDENTIAL_SERVICE,
+ Settings.Secure.CREDENTIAL_SERVICE_PRIMARY);
@Test
public void systemSettingsBackedUpOrDenied() {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a110f56d09bd..8b3fd41b62a6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -17,12 +17,12 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.shell"
- coreApp="true"
- android:sharedUserId="android.uid.shell"
- >
+ package="com.android.shell"
+ coreApp="true"
+ android:sharedUserId="android.uid.shell"
+ >
- <!-- Standard permissions granted to the shell. -->
+ <!-- Standard permissions granted to the shell. -->
<uses-permission android:name="android.permission.MANAGE_HEALTH_PERMISSIONS" />
<uses-permission android:name="android.permission.MANAGE_HEALTH_DATA" />
<uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTE" />
@@ -125,7 +125,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
- <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- BLUETOOTH_PRIVILEGED is needed for testing purposes only. -->
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
@@ -136,7 +136,7 @@
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.MANAGE_USB" />
<uses-permission android:name="android.permission.USE_RESERVED_DISK" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- System tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
@@ -231,16 +231,16 @@
<uses-permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS" />
<uses-permission android:name="android.permission.CLEAR_FREEZE_PERIOD" />
<uses-permission android:name="android.permission.MODIFY_QUIET_MODE" />
- <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
- <uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE"/>
- <uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL"/>
+ <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE" />
+ <uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE" />
+ <uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL" />
<uses-permission android:name="android.permission.BLUETOOTH_STACK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
<uses-permission android:name="android.permission.FRAME_STATS" />
<uses-permission android:name="android.permission.BIND_APPWIDGET" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
- <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
+ <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS" />
<uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" />
<uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
@@ -304,7 +304,7 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.BACKGROUND_CAMERA" />
<uses-permission android:name="android.permission.SYSTEM_CAMERA" />
- <!-- Permissions needed to test onCameraOpened/Closed callbacks -->
+ <!-- Permissions needed to test onCameraOpened/Closed callbacks -->
<uses-permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER" />
<!-- Permissions needed for CTS camera test: RecordingTest.java when assuming shell id -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
@@ -344,7 +344,7 @@
<uses-permission android:name="android.permission.LOADER_USAGE_STATS" />
<!-- Permission required for storage tests - FuseDaemonHostTest -->
- <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- Permission needed to run network tests in CTS -->
<uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
@@ -386,54 +386,54 @@
<uses-permission android:name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE" />
<!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES" />
<!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
- <uses-permission android:name="android.permission.START_CROSS_PROFILE_ACTIVITIES"/>
+ <uses-permission android:name="android.permission.START_CROSS_PROFILE_ACTIVITIES" />
<!-- permissions required for CTS test - PhoneStateListenerTest -->
<uses-permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH" />
<!-- Permissions required for granting and logging -->
- <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
- <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
- <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"/>
- <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD" />
<!-- Permission required for CTS test - BatterySaverTest -->
- <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
+ <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" />
<!-- Permission required for CTS test - UiModeManagerTest -->
- <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
- <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
+ <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
+ <uses-permission android:name="android.permission.READ_PROJECTION_STATE" />
<!-- Permission required for CTS tests - UiModeManagerTest, CarModeInCallServiceTest -->
- <uses-permission android:name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION"/>
+ <uses-permission android:name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION" />
<!-- Permission required for CTS test - SystemConfigTest -->
- <uses-permission android:name="android.permission.READ_CARRIER_APP_INFO"/>
+ <uses-permission android:name="android.permission.READ_CARRIER_APP_INFO" />
<!-- Permission required for CTS test - CarModeInCallServiceTest -->
- <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+ <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
<!-- Permission requried for CTS test - CellBroadcastIntentsTest -->
- <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"/>
+ <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS" />
<!-- Permission required for CTS test - TetheringManagerTest -->
- <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
+ <uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
<!-- Permission required for CTS test - CtsOsTestCases -->
- <uses-permission android:name="android.permission.MANAGE_CRATES"/>
+ <uses-permission android:name="android.permission.MANAGE_CRATES" />
<!-- Allows setting brightness from the shell -->
- <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS"/>
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
<!-- Permission required for CTS test - ShortcutManagerUsageTest -->
- <uses-permission android:name="android.permission.ACCESS_SHORTCUTS"/>
+ <uses-permission android:name="android.permission.ACCESS_SHORTCUTS" />
<!-- Permissions required for CTS test - UsageStatsTest -->
- <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
- <uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS" />
<!-- Permission needed for CTS test - MusicRecognitionManagerTest -->
<uses-permission android:name="android.permission.MANAGE_MUSIC_RECOGNITION" />
@@ -442,8 +442,8 @@
<uses-permission android:name="android.permission.MANAGE_SPEECH_RECOGNITION" />
<!-- Permissions required to test ambient display. -->
- <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
- <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
+ <uses-permission android:name="android.permission.READ_DREAM_STATE" />
+ <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
<!-- Permission required for CTS test - CtsLightsManagerTest -->
<uses-permission android:name="android.permission.CONTROL_DEVICE_LIGHTS" />
@@ -470,7 +470,7 @@
<uses-permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE" />
<!-- Permission required for testing system audio effect APIs. -->
- <uses-permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"/>
+ <uses-permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS" />
<!-- Permission required for running networking unit tests -->
<uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
@@ -495,7 +495,7 @@
<uses-permission android:name="android.permission.TV_INPUT_HARDWARE" />
<uses-permission android:name="android.permission.TIS_EXTENSION_INTERFACE" />
<uses-permission android:name="com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS" />
- <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
+ <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
<!-- Permission needed for CTS test - PrivilegedLocationPermissionTest -->
<uses-permission android:name="android.permission.LOCATION_HARDWARE" />
@@ -560,14 +560,14 @@
<uses-permission android:name="android.permission.BIND_CARRIER_SERVICES" />
<!-- Allows overriding the system's device state from the shell -->
- <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE"/>
+ <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE" />
<!-- Permissions required for CTS tests to close system dialogs -->
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
<!-- Permissions required for CTS test - HideOverlayWindowsTest -->
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
- <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"/>
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
<!-- Permission required for CTS test - CtsHdmiCecHostTestCases -->
<uses-permission android:name="android.permission.HDMI_CEC" />
@@ -630,21 +630,21 @@
<uses-permission android:name="android.permission.UPDATE_FONTS" />
<!-- Permission required for Launcher testing - DigitalWellbeingToastTest -->
- <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"/>
+ <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
<!-- Permission required for hotword detection service CTS tests -->
<uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
<uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
<!-- Permission required for CTS test - CtsVoiceInteractionTestCases -->
- <uses-permission android:name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
+ <uses-permission android:name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER" />
<uses-permission android:name="android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE" />
<!-- Permission required for CTS test - KeyguardLockedStateApiTest -->
<uses-permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" />
- <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
+ <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION" />
<!-- Permission required for CTS test - MediaCodecResourceTest -->
<uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" />
@@ -820,8 +820,8 @@
<uses-permission android:name="android.permission.DELETE_STAGED_HEALTH_CONNECT_REMOTE_DATA" />
<uses-permission android:name="android.permission.STAGE_HEALTH_CONNECT_REMOTE_DATA" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
<!-- Permissions required for CTS test - CtsBroadcastRadioTestCases -->
<uses-permission android:name="android.permission.ACCESS_BROADCAST_RADIO" />
@@ -832,12 +832,17 @@
<!-- Permission required for CTS test - CtsTelephonyProviderTestCases -->
<uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
- <uses-permission android:name="android.permission.LOG_FOREGROUND_RESOURCE_USE"/>
-
- <application android:label="@string/app_label"
- android:theme="@android:style/Theme.DeviceDefault.DayNight"
- android:defaultToDeviceProtectedStorage="true"
- android:directBootAware="true">
+ <uses-permission android:name="android.permission.LOG_FOREGROUND_RESOURCE_USE" />
+ <!-- Permission required for GTS test - GtsAttestationVerificationDeviceSideTestCases -->
+ <uses-permission android:name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE" />
+ <!-- Permission required for GTS test - GtsCredentialsTestCases -->
+ <uses-permission android:name="android.permission.LAUNCH_CREDENTIAL_SELECTOR" />
+
+ <application
+ android:label="@string/app_label"
+ android:theme="@android:style/Theme.DeviceDefault.DayNight"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.android.shell"
@@ -860,10 +865,11 @@
</intent-filter>
</provider>
- <provider android:name=".HeapDumpProvider"
- android:authorities="com.android.shell.heapdump"
- android:grantUriPermissions="true"
- android:exported="false" />
+ <provider
+ android:name=".HeapDumpProvider"
+ android:authorities="com.android.shell.heapdump"
+ android:grantUriPermissions="true"
+ android:exported="false" />
<activity
android:name=".BugreportWarningActivity"
@@ -872,13 +878,14 @@
android:excludeFromRecents="true"
android:exported="false" />
- <activity android:name=".HeapDumpActivity"
- android:theme="@*android:style/Theme.Translucent.NoTitleBar"
- android:label="@*android:string/dump_heap_title"
- android:finishOnCloseSystemDialogs="true"
- android:noHistory="true"
- android:excludeFromRecents="true"
- android:exported="false" />
+ <activity
+ android:name=".HeapDumpActivity"
+ android:theme="@*android:style/Theme.Translucent.NoTitleBar"
+ android:label="@*android:string/dump_heap_title"
+ android:finishOnCloseSystemDialogs="true"
+ android:noHistory="true"
+ android:excludeFromRecents="true"
+ android:exported="false" />
<receiver
android:name=".BugreportRequestedReceiver"
@@ -903,7 +910,7 @@
<receiver
android:name=".ProfcollectUploadReceiver"
android:exported="true"
- android:permission="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD" >
+ android:permission="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD">
<intent-filter>
<action android:name="com.android.shell.action.PROFCOLLECT_UPLOAD" />
</intent-filter>
@@ -912,6 +919,6 @@
<service
android:name=".BugreportProgressService"
android:foregroundServiceType="systemExempted"
- android:exported="false"/>
+ android:exported="false" />
</application>
</manifest>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index e6bbf9759651..6a7b8cdfceec 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -158,6 +158,7 @@ android_library {
"SystemUIAnimationLib",
"SystemUICommon",
"SystemUICustomizationLib",
+ "SystemUILogLib",
"SystemUIPluginLib",
"SystemUISharedLib",
"SystemUI-statsd",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index c8eb4b41f003..a27f113177c7 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -82,6 +82,7 @@
<uses-permission android:name="android.permission.CONTROL_VPN" />
<uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
<uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL"/>
+ <uses-permission android:name="android.permission.LOCATION_HARDWARE" />
<!-- Physical hardware -->
<uses-permission android:name="android.permission.MANAGE_USB" />
<uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index 5b5871f95fb3..8eb012d2e41c 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -43,6 +43,7 @@ android_library {
"androidx.core_core-ktx",
"androidx.annotation_annotation",
"SystemUIShaderLib",
+ "animationlib",
],
manifest: "AndroidManifest.xml",
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 94b37403b232..4037fd4a09d8 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -39,9 +39,9 @@ import android.view.animation.Interpolator
import android.view.animation.PathInterpolator
import androidx.annotation.BinderThread
import androidx.annotation.UiThread
+import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
-import java.lang.IllegalArgumentException
import kotlin.math.roundToInt
private const val TAG = "ActivityLaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index 42a86363bf01..48dd08f206c1 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -33,10 +33,10 @@ import android.view.WindowInsets
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
import android.widget.FrameLayout
+import com.android.app.animation.Interpolators
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CujType
import com.android.systemui.util.registerAnimationOnBackInvoked
-import java.lang.IllegalArgumentException
import kotlin.math.roundToInt
private const val TAG = "DialogLaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
deleted file mode 100644
index 9dbb9205b90e..000000000000
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.animation;
-
-import android.graphics.Path;
-import android.util.MathUtils;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.BounceInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.PathInterpolator;
-
-/**
- * Utility class to receive interpolators from.
- *
- * Make sure that changes made to this class are also reflected in {@link InterpolatorsAndroidX}.
- * Please consider using the androidx dependencies featuring better testability altogether.
- */
-public class Interpolators {
-
- /*
- * ============================================================================================
- * Emphasized interpolators.
- * ============================================================================================
- */
-
- /**
- * The default emphasized interpolator. Used for hero / emphasized movement of content.
- */
- public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
-
- /**
- * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
- * is disappearing e.g. when moving off screen.
- */
- public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
- 0.3f, 0f, 0.8f, 0.15f);
-
- /**
- * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
- * is appearing e.g. when coming from off screen
- */
- public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
- 0.05f, 0.7f, 0.1f, 1f);
-
-
- /*
- * ============================================================================================
- * Standard interpolators.
- * ============================================================================================
- */
-
- /**
- * The standard interpolator that should be used on every normal animation
- */
- public static final Interpolator STANDARD = new PathInterpolator(
- 0.2f, 0f, 0f, 1f);
-
- /**
- * The standard accelerating interpolator that should be used on every regular movement of
- * content that is disappearing e.g. when moving off screen.
- */
- public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(
- 0.3f, 0f, 1f, 1f);
-
- /**
- * The standard decelerating interpolator that should be used on every regular movement of
- * content that is appearing e.g. when coming from off screen.
- */
- public static final Interpolator STANDARD_DECELERATE = new PathInterpolator(
- 0f, 0f, 0f, 1f);
-
- /*
- * ============================================================================================
- * Legacy
- * ============================================================================================
- */
-
- /**
- * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN.
- */
- public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
-
- /**
- * The default legacy accelerating interpolator as defined in Material 1.
- * Also known as FAST_OUT_LINEAR_IN.
- */
- public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f);
-
- /**
- * The default legacy decelerating interpolator as defined in Material 1.
- * Also known as LINEAR_OUT_SLOW_IN.
- */
- public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f);
-
- /**
- * Linear interpolator. Often used if the interpolator is for different properties who need
- * different interpolations.
- */
- public static final Interpolator LINEAR = new LinearInterpolator();
-
- /*
- * ============================================================================================
- * Custom interpolators
- * ============================================================================================
- */
-
- public static final Interpolator FAST_OUT_SLOW_IN = LEGACY;
- public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE;
- public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE;
-
- /**
- * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
- * goes from 1 to 0 instead of 0 to 1).
- */
- public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
- new PathInterpolator(0.8f, 0f, 0.6f, 1f);
- public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
- public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
- public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
- public static final Interpolator ACCELERATE = new AccelerateInterpolator();
- public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
- public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
- public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
- public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
- public static final Interpolator ICON_OVERSHOT_LESS = new PathInterpolator(0.4f, 0f, 0.2f,
- 1.1f);
- public static final Interpolator PANEL_CLOSE_ACCELERATED = new PathInterpolator(0.3f, 0, 0.5f,
- 1);
- public static final Interpolator BOUNCE = new BounceInterpolator();
- /**
- * For state transitions on the control panel that lives in GlobalActions.
- */
- public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f,
- 1.0f);
-
- /**
- * Interpolator to be used when animating a move based on a click. Pair with enough duration.
- */
- public static final Interpolator TOUCH_RESPONSE =
- new PathInterpolator(0.3f, 0f, 0.1f, 1f);
-
- /**
- * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t
- * goes from 1 to 0 instead of 0 to 1).
- */
- public static final Interpolator TOUCH_RESPONSE_REVERSE =
- new PathInterpolator(0.9f, 0f, 0.7f, 1f);
-
- /*
- * ============================================================================================
- * Functions / Utilities
- * ============================================================================================
- */
-
- /**
- * Calculate the amount of overshoot using an exponential falloff function with desired
- * properties, where the overshoot smoothly transitions at the 1.0f boundary into the
- * overshoot, retaining its acceleration.
- *
- * @param progress a progress value going from 0 to 1
- * @param overshootAmount the amount > 0 of overshoot desired. A value of 0.1 means the max
- * value of the overall progress will be at 1.1.
- * @param overshootStart the point in (0,1] where the result should reach 1
- * @return the interpolated overshoot
- */
- public static float getOvershootInterpolation(float progress, float overshootAmount,
- float overshootStart) {
- if (overshootAmount == 0.0f || overshootStart == 0.0f) {
- throw new IllegalArgumentException("Invalid values for overshoot");
- }
- float b = MathUtils.log((overshootAmount + 1) / (overshootAmount)) / overshootStart;
- return MathUtils.max(0.0f,
- (float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
- }
-
- /**
- * Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
- * starts immediately here, instead of first having a section of non-overshooting
- *
- * @param progress a progress value going from 0 to 1
- */
- public static float getOvershootInterpolation(float progress) {
- return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
- }
-
- // Create the default emphasized interpolator
- private static PathInterpolator createEmphasizedInterpolator() {
- Path path = new Path();
- // Doing the same as fast_out_extra_slow_in
- path.moveTo(0f, 0f);
- path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
- path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
- return new PathInterpolator(path);
- }
-}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java b/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
deleted file mode 100644
index 8da87feb1fee..000000000000
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.animation;
-
-import android.graphics.Path;
-import android.util.MathUtils;
-
-import androidx.core.animation.AccelerateDecelerateInterpolator;
-import androidx.core.animation.AccelerateInterpolator;
-import androidx.core.animation.BounceInterpolator;
-import androidx.core.animation.DecelerateInterpolator;
-import androidx.core.animation.Interpolator;
-import androidx.core.animation.LinearInterpolator;
-import androidx.core.animation.PathInterpolator;
-
-/**
- * Utility class to receive interpolators from. (androidx compatible version)
- *
- * This is the androidx compatible version of {@link Interpolators}. Make sure that changes made to
- * this class are also reflected in {@link Interpolators}.
- *
- * Using the androidx versions of {@link androidx.core.animation.ValueAnimator} or
- * {@link androidx.core.animation.ObjectAnimator} improves animation testability. This file provides
- * the androidx compatible versions of the interpolators defined in {@link Interpolators}.
- * AnimatorTestRule can be used in Tests to manipulate the animation under test (e.g. artificially
- * advancing the time).
- */
-public class InterpolatorsAndroidX {
-
- /*
- * ============================================================================================
- * Emphasized interpolators.
- * ============================================================================================
- */
-
- /**
- * The default emphasized interpolator. Used for hero / emphasized movement of content.
- */
- public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
-
- /**
- * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
- * is disappearing e.g. when moving off screen.
- */
- public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
- 0.3f, 0f, 0.8f, 0.15f);
-
- /**
- * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
- * is appearing e.g. when coming from off screen
- */
- public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
- 0.05f, 0.7f, 0.1f, 1f);
-
-
- /*
- * ============================================================================================
- * Standard interpolators.
- * ============================================================================================
- */
-
- /**
- * The standard interpolator that should be used on every normal animation
- */
- public static final Interpolator STANDARD = new PathInterpolator(
- 0.2f, 0f, 0f, 1f);
-
- /**
- * The standard accelerating interpolator that should be used on every regular movement of
- * content that is disappearing e.g. when moving off screen.
- */
- public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(
- 0.3f, 0f, 1f, 1f);
-
- /**
- * The standard decelerating interpolator that should be used on every regular movement of
- * content that is appearing e.g. when coming from off screen.
- */
- public static final Interpolator STANDARD_DECELERATE = new PathInterpolator(
- 0f, 0f, 0f, 1f);
-
- /*
- * ============================================================================================
- * Legacy
- * ============================================================================================
- */
-
- /**
- * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN.
- */
- public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
-
- /**
- * The default legacy accelerating interpolator as defined in Material 1.
- * Also known as FAST_OUT_LINEAR_IN.
- */
- public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f);
-
- /**
- * The default legacy decelerating interpolator as defined in Material 1.
- * Also known as LINEAR_OUT_SLOW_IN.
- */
- public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f);
-
- /**
- * Linear interpolator. Often used if the interpolator is for different properties who need
- * different interpolations.
- */
- public static final Interpolator LINEAR = new LinearInterpolator();
-
- /*
- * ============================================================================================
- * Custom interpolators
- * ============================================================================================
- */
-
- public static final Interpolator FAST_OUT_SLOW_IN = LEGACY;
- public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE;
- public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE;
-
- /**
- * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
- * goes from 1 to 0 instead of 0 to 1).
- */
- public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
- new PathInterpolator(0.8f, 0f, 0.6f, 1f);
- public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
- public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
- public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
- public static final Interpolator ACCELERATE = new AccelerateInterpolator();
- public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
- public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
- public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
- public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
- public static final Interpolator ICON_OVERSHOT_LESS = new PathInterpolator(0.4f, 0f, 0.2f,
- 1.1f);
- public static final Interpolator PANEL_CLOSE_ACCELERATED = new PathInterpolator(0.3f, 0, 0.5f,
- 1);
- public static final Interpolator BOUNCE = new BounceInterpolator();
- /**
- * For state transitions on the control panel that lives in GlobalActions.
- */
- public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f,
- 1.0f);
-
- /**
- * Interpolator to be used when animating a move based on a click. Pair with enough duration.
- */
- public static final Interpolator TOUCH_RESPONSE =
- new PathInterpolator(0.3f, 0f, 0.1f, 1f);
-
- /**
- * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t
- * goes from 1 to 0 instead of 0 to 1).
- */
- public static final Interpolator TOUCH_RESPONSE_REVERSE =
- new PathInterpolator(0.9f, 0f, 0.7f, 1f);
-
- /*
- * ============================================================================================
- * Functions / Utilities
- * ============================================================================================
- */
-
- /**
- * Calculate the amount of overshoot using an exponential falloff function with desired
- * properties, where the overshoot smoothly transitions at the 1.0f boundary into the
- * overshoot, retaining its acceleration.
- *
- * @param progress a progress value going from 0 to 1
- * @param overshootAmount the amount > 0 of overshoot desired. A value of 0.1 means the max
- * value of the overall progress will be at 1.1.
- * @param overshootStart the point in (0,1] where the result should reach 1
- * @return the interpolated overshoot
- */
- public static float getOvershootInterpolation(float progress, float overshootAmount,
- float overshootStart) {
- if (overshootAmount == 0.0f || overshootStart == 0.0f) {
- throw new IllegalArgumentException("Invalid values for overshoot");
- }
- float b = MathUtils.log((overshootAmount + 1) / (overshootAmount)) / overshootStart;
- return MathUtils.max(0.0f,
- (float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
- }
-
- /**
- * Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
- * starts immediately here, instead of first having a section of non-overshooting
- *
- * @param progress a progress value going from 0 to 1
- */
- public static float getOvershootInterpolation(float progress) {
- return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
- }
-
- // Create the default emphasized interpolator
- private static PathInterpolator createEmphasizedInterpolator() {
- Path path = new Path();
- // Doing the same as fast_out_extra_slow_in
- path.moveTo(0f, 0f);
- path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
- path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
- return new PathInterpolator(path);
- }
-}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
index 3417ffd6b83a..142fd21d4a16 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
@@ -28,7 +28,7 @@ import android.util.MathUtils
import android.view.View
import android.view.ViewGroup
import android.view.animation.Interpolator
-import com.android.systemui.animation.Interpolators.LINEAR
+import com.android.app.animation.Interpolators.LINEAR
import kotlin.math.roundToInt
private const val TAG = "LaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index 9346a2f7ebb7..00108940e6ec 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -23,8 +23,8 @@ import android.animation.ValueAnimator
import android.graphics.Canvas
import android.graphics.Typeface
import android.graphics.fonts.Font
+import android.graphics.fonts.FontVariationAxis
import android.text.Layout
-import android.text.TextPaint
import android.util.LruCache
private const val DEFAULT_ANIMATION_DURATION: Long = 300
@@ -33,18 +33,39 @@ private const val TYPEFACE_CACHE_MAX_ENTRIES = 5
typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
interface TypefaceVariantCache {
- fun getTypefaceForVariant(fvar: String, targetPaint: TextPaint): Typeface?
+ fun getTypefaceForVariant(fvar: String?): Typeface?
+
+ companion object {
+ fun createVariantTypeface(baseTypeface: Typeface, fVar: String?): Typeface {
+ if (fVar.isNullOrEmpty()) {
+ return baseTypeface
+ }
+
+ val axes = FontVariationAxis.fromFontVariationSettings(fVar).toMutableList()
+ axes.removeIf { !baseTypeface.isSupportedAxes(it.getOpenTypeTagValue()) }
+ if (axes.isEmpty()) {
+ return baseTypeface
+ }
+ return Typeface.createFromTypefaceWithVariation(baseTypeface, axes)
+ }
+ }
}
-class TypefaceVariantCacheImpl() : TypefaceVariantCache {
+class TypefaceVariantCacheImpl(
+ var baseTypeface: Typeface,
+) : TypefaceVariantCache {
private val cache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES)
- override fun getTypefaceForVariant(fvar: String, targetPaint: TextPaint): Typeface? {
+ override fun getTypefaceForVariant(fvar: String?): Typeface? {
+ if (fvar == null) {
+ return baseTypeface
+ }
cache.get(fvar)?.let {
return it
}
- targetPaint.fontVariationSettings = fvar
- return targetPaint.typeface?.also { cache.put(fvar, it) }
+ return TypefaceVariantCache
+ .createVariantTypeface(baseTypeface, fvar)
+ .also { cache.put(fvar, it) }
}
}
@@ -78,7 +99,7 @@ class TextAnimator(
layout: Layout,
private val invalidateCallback: () -> Unit,
) {
- var typefaceCache: TypefaceVariantCache = TypefaceVariantCacheImpl()
+ var typefaceCache: TypefaceVariantCache = TypefaceVariantCacheImpl(layout.paint.typeface)
get() = field
set(value) {
field = value
@@ -244,8 +265,7 @@ class TextAnimator(
}
if (!fvar.isNullOrBlank()) {
- textInterpolator.targetPaint.typeface =
- typefaceCache.getTypefaceForVariant(fvar, textInterpolator.targetPaint)
+ textInterpolator.targetPaint.typeface = typefaceCache.getTypefaceForVariant(fvar)
}
if (color != null) {
@@ -339,4 +359,3 @@ class TextAnimator(
)
}
}
-
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
index 79189bc3e5c3..8ed8d8fb61fd 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -38,6 +38,8 @@ class TextInterpolator(
* Once you modified the style parameters, you have to call reshapeText to recalculate base text
* layout.
*
+ * Do not bypass the cache and update the typeface or font variation directly.
+ *
* @return a paint object
*/
val basePaint = TextPaint(layout.paint)
@@ -48,6 +50,8 @@ class TextInterpolator(
* Once you modified the style parameters, you have to call reshapeText to recalculate target
* text layout.
*
+ * Do not bypass the cache and update the typeface or font variation directly.
+ *
* @return a paint object
*/
val targetPaint = TextPaint(layout.paint)
@@ -217,14 +221,8 @@ class TextInterpolator(
run.fontRuns.forEach { fontRun ->
fontRun.baseFont =
fontInterpolator.lerp(fontRun.baseFont, fontRun.targetFont, progress)
- val fvar = run {
- val tmpFontVariationsArray = mutableListOf<FontVariationAxis>()
- fontRun.baseFont.axes.forEach {
- tmpFontVariationsArray.add(FontVariationAxis(it.tag, it.styleValue))
- }
- FontVariationAxis.toFontVariationSettings(tmpFontVariationsArray)
- }
- basePaint.typeface = typefaceCache.getTypefaceForVariant(fvar, basePaint)
+ val fvar = FontVariationAxis.toFontVariationSettings(fontRun.baseFont.axes)
+ basePaint.typeface = typefaceCache.getTypefaceForVariant(fvar)
}
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
index 58ffef25cb42..8e79e3ce1742 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -25,6 +25,7 @@ import android.util.IntProperty
import android.view.View
import android.view.ViewGroup
import android.view.animation.Interpolator
+import com.android.app.animation.Interpolators
import kotlin.math.max
import kotlin.math.min
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
index f3d8b1782486..dd32851a97cf 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
@@ -19,7 +19,7 @@ package com.android.systemui.animation.back
import android.util.DisplayMetrics
import android.view.animation.Interpolator
import android.window.BackEvent
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.util.dpToPx
/** Used to convert [BackEvent] into a [BackTransformation]. */
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 3a19990f0627..8dd2c39e7a58 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -28,13 +28,13 @@ import android.text.format.DateFormat
import android.util.AttributeSet
import android.util.MathUtils.constrainedMap
import android.widget.TextView
+import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.GlyphCallback
-import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.TextAnimator
import com.android.systemui.customization.R
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
import java.io.PrintWriter
import java.util.Calendar
import java.util.Locale
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index b0c02407873c..aa1bb3f640ee 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -23,6 +23,12 @@ import android.os.UserHandle
import android.provider.Settings
import android.util.Log
import androidx.annotation.OpenForTesting
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogMessage
+import com.android.systemui.log.LogMessageImpl
+import com.android.systemui.log.MessageInitializer
+import com.android.systemui.log.MessagePrinter
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockId
import com.android.systemui.plugins.ClockMetadata
@@ -32,12 +38,6 @@ import com.android.systemui.plugins.ClockSettings
import com.android.systemui.plugins.PluginLifecycleManager
import com.android.systemui.plugins.PluginListener
import com.android.systemui.plugins.PluginManager
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogMessage
-import com.android.systemui.plugins.log.LogMessageImpl
-import com.android.systemui.plugins.log.MessageInitializer
-import com.android.systemui.plugins.log.MessagePrinter
import com.android.systemui.util.Assert
import java.io.PrintWriter
import java.util.concurrent.ConcurrentHashMap
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 2cc36008e4f8..6aa74fbf24e7 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -24,6 +24,7 @@ import android.view.View
import android.widget.FrameLayout
import androidx.annotation.VisibleForTesting
import com.android.systemui.customization.R
+import com.android.systemui.log.LogBuffer
import com.android.systemui.plugins.ClockAnimations
import com.android.systemui.plugins.ClockConfig
import com.android.systemui.plugins.ClockController
@@ -32,7 +33,6 @@ import com.android.systemui.plugins.ClockFaceConfig
import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockFaceEvents
import com.android.systemui.plugins.ClockSettings
-import com.android.systemui.plugins.log.LogBuffer
import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
diff --git a/packages/SystemUI/log/.gitignore b/packages/SystemUI/log/.gitignore
new file mode 100644
index 000000000000..f9a33dbbcc7e
--- /dev/null
+++ b/packages/SystemUI/log/.gitignore
@@ -0,0 +1,9 @@
+.idea/
+.gradle/
+gradle/
+build/
+gradlew*
+local.properties
+*.iml
+android.properties
+buildSrc \ No newline at end of file
diff --git a/packages/SystemUI/log/Android.bp b/packages/SystemUI/log/Android.bp
new file mode 100644
index 000000000000..627ac4b7c381
--- /dev/null
+++ b/packages/SystemUI/log/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+ name: "SystemUILogLib",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.core_core-ktx",
+ "androidx.annotation_annotation",
+ "error_prone_annotations",
+ "SystemUICommon",
+ ],
+ manifest: "AndroidManifest.xml",
+ kotlincflags: ["-Xjvm-default=all"],
+}
diff --git a/packages/SystemUI/log/AndroidManifest.xml b/packages/SystemUI/log/AndroidManifest.xml
new file mode 100644
index 000000000000..4021e1a5f751
--- /dev/null
+++ b/packages/SystemUI/log/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.log">
+
+
+</manifest>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLogger.kt b/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLogger.kt
index f95b1874da36..bc35095a3436 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLogger.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLogger.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.plugins.log
+package com.android.systemui.log
import com.google.errorprone.annotations.CompileTimeConstant
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLoggerImpl.kt b/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLoggerImpl.kt
index 91b39e6fcc13..6fc525369e8b 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLoggerImpl.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLoggerImpl.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.plugins.log
+package com.android.systemui.log
import com.google.errorprone.annotations.CompileTimeConstant
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt
index 0a7ccc525a73..af1a11f6597a 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.plugins.log
+package com.android.systemui.log
import android.os.Trace
import android.util.Log
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogLevel.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogLevel.kt
index b036cf0be1d6..7d9647a13149 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogLevel.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogLevel.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.plugins.log
+package com.android.systemui.log
import android.util.Log
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessage.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogMessage.kt
index 9468681289bf..88c34f82a089 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessage.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogMessage.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.plugins.log
+package com.android.systemui.log
import java.io.PrintWriter
import java.text.SimpleDateFormat
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessageImpl.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogMessageImpl.kt
index f2a6a91adcdf..5e10f783850f 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessageImpl.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogMessageImpl.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.plugins.log
+package com.android.systemui.log
/** Recyclable implementation of [LogMessage]. */
data class LogMessageImpl(
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTracker.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTracker.kt
index cfe894f276a0..55f3a738e4f1 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTracker.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTracker.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.plugins.log
+package com.android.systemui.log
/** Keeps track of which [LogBuffer] messages should also appear in logcat. */
interface LogcatEchoTracker {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
index 7a125ac14ea1..d0ad28f04670 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.plugins.log
+package com.android.systemui.log
import android.content.ContentResolver
import android.database.ContentObserver
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerProd.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerProd.kt
index 3c8bda4a44e0..56966773d1b0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerProd.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerProd.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.plugins.log
+package com.android.systemui.log
/** Production version of [LogcatEchoTracker] that isn't configurable. */
class LogcatEchoTrackerProd : LogcatEchoTracker {
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index e306d4aac398..fec093b26bcc 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/Android.bp
@@ -32,12 +32,14 @@ java_library {
"bcsmartspace/src/**/*.kt",
],
+ // If you add a static lib here, you may need to also add the package to the ClassLoaderFilter
+ // in PluginInstance. That will ensure that loaded plugins have access to the related classes.
static_libs: [
"androidx.annotation_annotation",
- "error_prone_annotations",
"PluginCoreLib",
"SystemUIAnimationLib",
"SystemUICommon",
+ "SystemUILogLib",
],
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index ca3e710a4acb..7bf139e69f2e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -18,8 +18,8 @@ import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.view.View
import com.android.internal.annotations.Keep
+import com.android.systemui.log.LogBuffer
import com.android.systemui.plugins.annotations.ProvidesInterface
-import com.android.systemui.plugins.log.LogBuffer
import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
diff --git a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
index 934fa6f54286..29832a081612 100644
--- a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
+++ b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
@@ -30,7 +30,7 @@
<FrameLayout
android:id="@+id/inout_container"
- android:layout_height="@*android:dimen/status_bar_system_icon_intrinsic_size"
+ android:layout_height="17dp"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical">
<ImageView
@@ -39,25 +39,24 @@
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_down"
android:visibility="gone"
- android:paddingEnd="2sp"
+ android:paddingEnd="2dp"
/>
<ImageView
android:id="@+id/mobile_out"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_up"
- android:paddingEnd="2sp"
+ android:paddingEnd="2dp"
android:visibility="gone"
/>
</FrameLayout>
<ImageView
android:id="@+id/mobile_type"
- android:layout_height="@dimen/status_bar_mobile_signal_size"
+ android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
- android:adjustViewBounds="true"
- android:paddingStart="2.5sp"
- android:paddingEnd="1sp"
+ android:paddingStart="2.5dp"
+ android:paddingEnd="1dp"
android:visibility="gone" />
<Space
android:id="@+id/mobile_roaming_space"
@@ -71,14 +70,14 @@
android:layout_gravity="center_vertical">
<com.android.systemui.statusbar.AnimatedImageView
android:id="@+id/mobile_signal"
- android:layout_height="@dimen/status_bar_mobile_signal_size"
- android:layout_width="@dimen/status_bar_mobile_signal_size"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
systemui:hasOverlappingRendering="false"
/>
<ImageView
android:id="@+id/mobile_roaming"
- android:layout_width="@dimen/status_bar_mobile_signal_size"
- android:layout_height="@dimen/status_bar_mobile_signal_size"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:src="@drawable/stat_sys_roaming"
android:contentDescription="@string/data_connection_roaming"
android:visibility="gone" />
diff --git a/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml b/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
index d123caf82ed5..cff2839e6f88 100644
--- a/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
+++ b/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
@@ -2,11 +2,11 @@
android:viewportWidth="22" android:width="20.166666dp" xmlns:android="http://schemas.android.com/apk/res/android">
<group>
<clip-path android:pathData="M0,0.5h22v11h-22z"/>
- <path android:fillColor="#231F20" android:pathData="M6.397,9.908H0V11.5H6.397V9.908Z"/>
- <path android:fillColor="#231F20" android:pathData="M14.199,9.908H7.801V11.5H14.199V9.908Z"/>
- <path android:fillColor="#231F20" android:pathData="M11.858,0.5H10.142V6.434H11.858V0.5Z"/>
- <path android:fillColor="#231F20" android:pathData="M8.348,7.129L3.885,2.975L3.823,2.932L2.668,4.003L2.621,4.046L7.084,8.2L7.146,8.243L8.301,7.172L8.348,7.129Z"/>
- <path android:fillColor="#231F20" android:pathData="M18.224,2.975L18.177,2.932L13.653,7.129L14.807,8.2L14.854,8.243L19.379,4.046L18.224,2.975Z"/>
- <path android:fillColor="#231F20" android:pathData="M22,9.908H15.603V11.5H22V9.908Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M6.397,9.908H0V11.5H6.397V9.908Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M14.199,9.908H7.801V11.5H14.199V9.908Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M11.858,0.5H10.142V6.434H11.858V0.5Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M8.348,7.129L3.885,2.975L3.823,2.932L2.668,4.003L2.621,4.046L7.084,8.2L7.146,8.243L8.301,7.172L8.348,7.129Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M18.224,2.975L18.177,2.932L13.653,7.129L14.807,8.2L14.854,8.243L19.379,4.046L18.224,2.975Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M22,9.908H15.603V11.5H22V9.908Z"/>
</group>
</vector>
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index e989372adde3..386c9d66a0c1 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -14,12 +14,17 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+
+<!--
+keep split_shade_status_bar height constant to avoid requestLayout calls on each
+frame when animating QS <-> QQS transition
+-->
<com.android.systemui.util.NoRemeasureMotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/split_shade_status_bar"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/qs_header_height"
android:minHeight="@dimen/large_screen_shade_header_min_height"
android:clickable="false"
android:focusable="true"
@@ -30,6 +35,14 @@
app:layoutDescription="@xml/combined_qs_header_scene">
<androidx.constraintlayout.widget.Guideline
+ android:id="@+id/qqs_header_bottom_guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_begin="@dimen/large_screen_shade_header_min_height"
+ />
+
+ <androidx.constraintlayout.widget.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/begin_guide"
@@ -126,7 +139,8 @@
<com.android.systemui.battery.BatteryMeterView
android:id="@+id/batteryRemainingIcon"
android:layout_width="wrap_content"
- android:layout_height="0dp"
+ android:layout_height="@dimen/large_screen_shade_header_min_height"
+ app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
app:layout_constrainedWidth="true"
app:textAppearance="@style/TextAppearance.QS.Status"
app:layout_constraintStart_toEndOf="@id/statusIcons"
diff --git a/packages/SystemUI/res/layout/smart_action_button.xml b/packages/SystemUI/res/layout/smart_action_button.xml
index 488be3a4479e..4e5785d284ee 100644
--- a/packages/SystemUI/res/layout/smart_action_button.xml
+++ b/packages/SystemUI/res/layout/smart_action_button.xml
@@ -29,8 +29,8 @@
android:textSize="@dimen/smart_reply_button_font_size"
android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
android:textColor="@color/smart_reply_button_text"
- android:paddingLeft="@dimen/smart_reply_button_action_padding_left"
- android:paddingRight="@dimen/smart_reply_button_padding_horizontal"
+ android:paddingStart="@dimen/smart_reply_button_action_padding_left"
+ android:paddingEnd="@dimen/smart_reply_button_padding_horizontal"
android:drawablePadding="@dimen/smart_action_button_icon_padding"
android:textStyle="normal"
android:ellipsize="none"/>
diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml
index ddf16e0afed7..b24362febbdd 100644
--- a/packages/SystemUI/res/layout/smart_reply_button.xml
+++ b/packages/SystemUI/res/layout/smart_reply_button.xml
@@ -31,7 +31,7 @@
android:textSize="@dimen/smart_reply_button_font_size"
android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
android:textColor="@color/smart_reply_button_text"
- android:paddingLeft="@dimen/smart_reply_button_padding_horizontal"
- android:paddingRight="@dimen/smart_reply_button_padding_horizontal"
+ android:paddingStart="@dimen/smart_reply_button_padding_horizontal"
+ android:paddingEnd="@dimen/smart_reply_button_padding_horizontal"
android:textStyle="normal"
android:ellipsize="none"/>
diff --git a/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml b/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml
index 473ab08a1935..0ea0653ab89f 100644
--- a/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml
+++ b/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml
@@ -24,11 +24,11 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
- android:layout_marginStart="2.5sp"
+ android:layout_marginStart="2.5dp"
>
<FrameLayout
android:id="@+id/inout_container"
- android:layout_height="@*android:dimen/status_bar_system_icon_intrinsic_size"
+ android:layout_height="17dp"
android:layout_width="wrap_content"
android:gravity="center_vertical" >
<ImageView
@@ -37,14 +37,14 @@
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_down"
android:visibility="gone"
- android:paddingEnd="2sp"
+ android:paddingEnd="2dp"
/>
<ImageView
android:id="@+id/wifi_out"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_up"
- android:paddingEnd="2sp"
+ android:paddingEnd="2dp"
android:visibility="gone"
/>
</FrameLayout>
@@ -62,7 +62,7 @@
<View
android:id="@+id/wifi_signal_spacer"
android:layout_width="@dimen/status_bar_wifi_signal_spacer_width"
- android:layout_height="4sp"
+ android:layout_height="4dp"
android:visibility="gone" />
<!-- Looks like CarStatusBar uses this... -->
@@ -75,7 +75,7 @@
<View
android:id="@+id/wifi_airplane_spacer"
android:layout_width="@dimen/status_bar_airplane_spacer_width"
- android:layout_height="4sp"
+ android:layout_height="4dp"
android:visibility="gone"
/>
</com.android.keyguard.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml b/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml
index 18386637e8f8..191158e4e8c2 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml
@@ -20,7 +20,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/udfps_animation_view_internal"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:contentDescription="@string/accessibility_fingerprint_label">
<!-- Background protection -->
<ImageView
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index f40615eb46d0..20864591ae5a 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -17,7 +17,7 @@
-->
<resources>
<!-- gap on either side of status bar notification icons -->
- <dimen name="status_bar_icon_padding">1sp</dimen>
+ <dimen name="status_bar_icon_padding">1dp</dimen>
<dimen name="controls_header_horizontal_padding">28dp</dimen>
<dimen name="controls_content_margin_horizontal">40dp</dimen>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index cb8c2a73c15d..db7eb7a049e7 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -207,11 +207,6 @@
<color name="controls_task_view_bg">#CC191C1D</color>
<color name="control_popup_dim">#8A000000</color>
- <!-- Keyboard backlight indicator-->
- <color name="backlight_indicator_step_filled">#F6E388</color>
- <color name="backlight_indicator_step_empty">#494740</color>
- <color name="backlight_indicator_background">#32302A</color>
-
<!-- Docked misalignment message -->
<color name="misalignment_text_color">#F28B82</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f5c4a4e4bb52..aff0e8052739 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -122,26 +122,26 @@
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
<!-- Default horizontal drawable padding for status bar icons. -->
- <dimen name="status_bar_horizontal_padding">2.5sp</dimen>
+ <dimen name="status_bar_horizontal_padding">2.5dp</dimen>
<!-- Height of the battery icon in the status bar. -->
- <dimen name="status_bar_battery_icon_height">13.0sp</dimen>
+ <dimen name="status_bar_battery_icon_height">13.0dp</dimen>
<!-- Width of the battery icon in the status bar. The battery drawable assumes a 12x20 canvas,
- so the width of the icon should be 13.0sp * (12.0 / 20.0) -->
- <dimen name="status_bar_battery_icon_width">7.8sp</dimen>
+ so the width of the icon should be 13.0dp * (12.0 / 20.0) -->
+ <dimen name="status_bar_battery_icon_width">7.8dp</dimen>
- <!-- The battery icon is 13sp tall, but the other system icons are 15sp tall (see
+ <!-- The battery icon is 13dp tall, but the other system icons are 15dp tall (see
@*android:dimen/status_bar_system_icon_size) with some top and bottom padding embedded in
- the drawables themselves. So, the battery icon may need an extra 1sp of spacing so that its
+ the drawables themselves. So, the battery icon may need an extra 1dp of spacing so that its
bottom still aligns with the bottom of all the other system icons. See b/258672854. -->
- <dimen name="status_bar_battery_extra_vertical_spacing">1sp</dimen>
+ <dimen name="status_bar_battery_extra_vertical_spacing">1dp</dimen>
<!-- The font size for the clock in the status bar. -->
<dimen name="status_bar_clock_size">14sp</dimen>
<!-- The starting padding for the clock in the status bar. -->
- <dimen name="status_bar_clock_starting_padding">7sp</dimen>
+ <dimen name="status_bar_clock_starting_padding">7dp</dimen>
<!-- The end padding for the clock in the status bar. -->
<dimen name="status_bar_clock_end_padding">0dp</dimen>
@@ -153,19 +153,16 @@
<dimen name="status_bar_left_clock_end_padding">2dp</dimen>
<!-- Spacing after the wifi signals that is present if there are any icons following it. -->
- <dimen name="status_bar_wifi_signal_spacer_width">2.5sp</dimen>
+ <dimen name="status_bar_wifi_signal_spacer_width">2.5dp</dimen>
<!-- Size of the view displaying the wifi signal icon in the status bar. -->
- <dimen name="status_bar_wifi_signal_size">13sp</dimen>
-
- <!-- Size of the view displaying the mobile signal icon in the status bar. -->
- <dimen name="status_bar_mobile_signal_size">13sp</dimen>
+ <dimen name="status_bar_wifi_signal_size">@*android:dimen/status_bar_system_icon_size</dimen>
<!-- Spacing before the airplane mode icon if there are any icons preceding it. -->
- <dimen name="status_bar_airplane_spacer_width">4sp</dimen>
+ <dimen name="status_bar_airplane_spacer_width">4dp</dimen>
<!-- Spacing between system icons. -->
- <dimen name="status_bar_system_icon_spacing">2sp</dimen>
+ <dimen name="status_bar_system_icon_spacing">0dp</dimen>
<!-- The amount to scale each of the status bar icons by. A value of 1 means no scaling. -->
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
@@ -313,7 +310,7 @@
<dimen name="snooze_snackbar_min_height">56dp</dimen>
<!-- size at which Notification icons will be drawn in the status bar -->
- <dimen name="status_bar_icon_drawing_size">15sp</dimen>
+ <dimen name="status_bar_icon_drawing_size">15dp</dimen>
<!-- size at which Notification icons will be drawn on Ambient Display -->
<dimen name="status_bar_icon_drawing_size_dark">
@@ -324,22 +321,22 @@
<item type="dimen" name="status_bar_icon_drawing_alpha">90%</item>
<!-- gap on either side of status bar notification icons -->
- <dimen name="status_bar_icon_padding">0sp</dimen>
+ <dimen name="status_bar_icon_padding">0dp</dimen>
<!-- the padding on the start of the statusbar -->
- <dimen name="status_bar_padding_start">8sp</dimen>
+ <dimen name="status_bar_padding_start">8dp</dimen>
<!-- the padding on the end of the statusbar -->
- <dimen name="status_bar_padding_end">8sp</dimen>
+ <dimen name="status_bar_padding_end">8dp</dimen>
<!-- the padding on the top of the statusbar (usually 0) -->
- <dimen name="status_bar_padding_top">0sp</dimen>
+ <dimen name="status_bar_padding_top">0dp</dimen>
<!-- the radius of the overflow dot in the status bar -->
- <dimen name="overflow_dot_radius">2sp</dimen>
+ <dimen name="overflow_dot_radius">2dp</dimen>
<!-- the padding between dots in the icon overflow -->
- <dimen name="overflow_icon_dot_padding">3sp</dimen>
+ <dimen name="overflow_icon_dot_padding">3dp</dimen>
<!-- Dimensions related to screenshots -->
@@ -618,10 +615,11 @@
<dimen name="qs_header_carrier_separator_width">6dp</dimen>
<dimen name="qs_carrier_margin_width">4dp</dimen>
<dimen name="qs_footer_icon_size">20dp</dimen>
+ <dimen name="qs_header_height">120dp</dimen>
<dimen name="qs_header_row_min_height">48dp</dimen>
- <dimen name="qs_header_non_clickable_element_height">24sp</dimen>
- <dimen name="new_qs_header_non_clickable_element_height">24sp</dimen>
+ <dimen name="qs_header_non_clickable_element_height">24dp</dimen>
+ <dimen name="new_qs_header_non_clickable_element_height">24dp</dimen>
<dimen name="qs_footer_padding">20dp</dimen>
<dimen name="qs_security_footer_height">88dp</dimen>
@@ -825,7 +823,7 @@
<!-- Padding between the mobile signal indicator and the start icon when the roaming icon
is displayed in the upper left corner. -->
- <dimen name="roaming_icon_start_padding">2sp</dimen>
+ <dimen name="roaming_icon_start_padding">2dp</dimen>
<!-- Extra padding between the mobile data type icon and the strength indicator when the data
type icon is wide for the tile in quick settings. -->
@@ -1045,13 +1043,13 @@
<dimen name="display_cutout_margin_consumption">0px</dimen>
<!-- Height of the Ongoing App Ops chip -->
- <dimen name="ongoing_appops_chip_height">24sp</dimen>
+ <dimen name="ongoing_appops_chip_height">24dp</dimen>
<!-- Side padding between background of Ongoing App Ops chip and content -->
<dimen name="ongoing_appops_chip_side_padding">8dp</dimen>
<!-- Margin between icons of Ongoing App Ops chip -->
<dimen name="ongoing_appops_chip_icon_margin">4dp</dimen>
<!-- Icon size of Ongoing App Ops chip -->
- <dimen name="ongoing_appops_chip_icon_size">16sp</dimen>
+ <dimen name="ongoing_appops_chip_icon_size">16dp</dimen>
<!-- Radius of Ongoing App Ops chip corners -->
<dimen name="ongoing_appops_chip_bg_corner_radius">28dp</dimen>
<!-- One or two privacy items -->
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 499dfa4b3c9f..eaeaabe8779a 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -198,6 +198,9 @@
<item type="id" name="pm_lite"/>
<item type="id" name="settings_button_container"/>
+ <!--Keyboard Backlight Dialog -->
+ <item type="id" name="keyboard_backlight_dialog_container"/>
+
<item type="id" name="log_access_dialog_allow_button" />
<item type="id" name="log_access_dialog_deny_button" />
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a51afe905354..c57fef1c52f7 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3042,14 +3042,14 @@
Requirement for the notes app to be available for the user to use. This is shown as part of a
bulleted list of requirements. When all requirements are met, the app can be accessed through a
shortcut button on the lock screen. [CHAR LIMIT=NONE] -->
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction">Select a default notes app to use notetaking shortcut</string>
+ <string name="keyguard_affordance_enablement_dialog_notes_app_instruction">Select a default notes app to use the notetaking shortcut</string>
<!---
The action to make the lock screen shortcut for the notes app to be available for the user to
use. This is shown as the action button in the dialog listing the requirements. When all
requirements are met, the app can be accessed through a shortcut button on the lock screen.
[CHAR LIMIT=NONE] -->
- <string name="keyguard_affordance_enablement_dialog_notes_app_action">Open settings</string>
+ <string name="keyguard_affordance_enablement_dialog_notes_app_action">Select app</string>
<!--
Error message shown when a shortcut must be pressed and held to activate it, usually shown when
diff --git a/packages/SystemUI/res/xml/qqs_header.xml b/packages/SystemUI/res/xml/qqs_header.xml
index 00a0444a1c9d..1950965fc298 100644
--- a/packages/SystemUI/res/xml/qqs_header.xml
+++ b/packages/SystemUI/res/xml/qqs_header.xml
@@ -28,7 +28,7 @@
android:layout_height="@dimen/large_screen_shade_header_min_height"
app:layout_constraintStart_toStartOf="@id/begin_guide"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
app:layout_constraintEnd_toStartOf="@id/date"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
@@ -62,7 +62,7 @@
app:layout_constraintStart_toEndOf="@id/date"
app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintHorizontal_chainStyle="packed"
/>
@@ -77,7 +77,7 @@
app:layout_constraintStart_toEndOf="@id/statusIcons"
app:layout_constraintEnd_toEndOf="@id/end_guide"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintHorizontal_chainStyle="packed"
/>
@@ -105,7 +105,7 @@
app:layout_constraintStart_toEndOf="@id/date"
app:layout_constraintEnd_toEndOf="@id/end_guide"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
app:layout_constraintHorizontal_bias="1"
/>
</Constraint>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt
index 2d83458ec2f7..a2b6e2cf9ae3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt
@@ -16,27 +16,179 @@
package com.android.systemui.shared.condition
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.launch
+
/**
* A higher order [Condition] which combines multiple conditions with a specified
- * [Evaluator.ConditionOperand].
+ * [Evaluator.ConditionOperand]. Conditions are executed lazily as-needed.
+ *
+ * @param scope The [CoroutineScope] to execute in.
+ * @param conditions The list of conditions to evaluate. Since conditions are executed lazily, the
+ * ordering is important here.
+ * @param operand The [Evaluator.ConditionOperand] to apply to the conditions.
*/
-internal class CombinedCondition
+@OptIn(ExperimentalCoroutinesApi::class)
+class CombinedCondition
constructor(
+ private val scope: CoroutineScope,
private val conditions: Collection<Condition>,
@Evaluator.ConditionOperand private val operand: Int
-) : Condition(null, false), Condition.Callback {
+) : Condition(scope, null, false) {
+
+ private var job: Job? = null
+ private val _startStrategy by lazy { calculateStartStrategy() }
override fun start() {
- onConditionChanged(this)
- conditions.forEach { it.addCallback(this) }
- }
+ job =
+ scope.launch {
+ val groupedConditions = conditions.groupBy { it.isOverridingCondition }
- override fun onConditionChanged(condition: Condition) {
- Evaluator.evaluate(conditions, operand)?.also { value -> updateCondition(value) }
- ?: clearCondition()
+ lazilyEvaluate(
+ conditions = groupedConditions.getOrDefault(true, emptyList()),
+ filterUnknown = true
+ )
+ .distinctUntilChanged()
+ .flatMapLatest { overriddenValue ->
+ // If there are overriding conditions with values set, they take precedence.
+ if (overriddenValue == null) {
+ lazilyEvaluate(
+ conditions = groupedConditions.getOrDefault(false, emptyList()),
+ filterUnknown = false
+ )
+ } else {
+ flowOf(overriddenValue)
+ }
+ }
+ .collect { conditionMet ->
+ if (conditionMet == null) {
+ clearCondition()
+ } else {
+ updateCondition(conditionMet)
+ }
+ }
+ }
}
override fun stop() {
- conditions.forEach { it.removeCallback(this) }
+ job?.cancel()
+ job = null
+ }
+
+ /**
+ * Evaluates a list of conditions lazily with support for short-circuiting. Conditions are
+ * executed serially in the order provided. At any point if the result can be determined, we
+ * short-circuit and return the result without executing all conditions.
+ */
+ private fun lazilyEvaluate(
+ conditions: Collection<Condition>,
+ filterUnknown: Boolean,
+ ): Flow<Boolean?> = callbackFlow {
+ val jobs = MutableList<Job?>(conditions.size) { null }
+ val values = MutableList<Boolean?>(conditions.size) { null }
+ val flows = conditions.map { it.toFlow() }
+
+ fun cancelAllExcept(indexToSkip: Int) {
+ for (index in 0 until jobs.size) {
+ if (index == indexToSkip) {
+ continue
+ }
+ if (
+ indexToSkip == -1 ||
+ conditions.elementAt(index).startStrategy == START_WHEN_NEEDED
+ ) {
+ jobs[index]?.cancel()
+ jobs[index] = null
+ values[index] = null
+ }
+ }
+ }
+
+ fun collectFlow(index: Int) {
+ // Base case which is triggered once we have collected all the flows. In this case,
+ // we never short-circuited and therefore should return the fully evaluated
+ // conditions.
+ if (flows.isEmpty() || index == -1) {
+ val filteredValues =
+ if (filterUnknown) {
+ values.filterNotNull()
+ } else {
+ values
+ }
+ trySend(Evaluator.evaluate(filteredValues, operand))
+ return
+ }
+ jobs[index] =
+ scope.launch {
+ flows.elementAt(index).collect { value ->
+ values[index] = value
+ if (shouldEarlyReturn(value)) {
+ trySend(value)
+ // The overall result is contingent on this condition, so we don't need
+ // to monitor any other conditions.
+ cancelAllExcept(index)
+ } else {
+ collectFlow(jobs.indexOfFirst { it == null })
+ }
+ }
+ }
+ }
+
+ // Collect any eager conditions immediately.
+ var started = false
+ for ((index, condition) in conditions.withIndex()) {
+ if (condition.startStrategy == START_EAGERLY) {
+ collectFlow(index)
+ started = true
+ }
+ }
+
+ // If no eager conditions started, start the first condition to kick off evaluation.
+ if (!started) {
+ collectFlow(0)
+ }
+ awaitClose { cancelAllExcept(-1) }
+ }
+
+ private fun shouldEarlyReturn(conditionMet: Boolean?): Boolean {
+ return when (operand) {
+ Evaluator.OP_AND -> conditionMet == false
+ Evaluator.OP_OR -> conditionMet == true
+ else -> false
+ }
+ }
+
+ /**
+ * Calculate the start strategy for this condition. This depends on the strategies of the child
+ * conditions. If there are any eager conditions, we must also start this condition eagerly. In
+ * the absence of eager conditions, we check for lazy conditions. In the absence of either, we
+ * make the condition only start when needed.
+ */
+ private fun calculateStartStrategy(): Int {
+ var startStrategy = START_WHEN_NEEDED
+ for (condition in conditions) {
+ when (condition.startStrategy) {
+ START_EAGERLY -> return START_EAGERLY
+ START_LAZILY -> {
+ startStrategy = START_LAZILY
+ }
+ START_WHEN_NEEDED -> {
+ // this is the default, so do nothing
+ }
+ }
+ }
+ return startStrategy
+ }
+
+ override fun getStartStrategy(): Int {
+ return _startStrategy
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java
index cc48090e1217..6bf1ce57b01e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java
@@ -18,11 +18,14 @@ package com.android.systemui.shared.condition;
import android.util.Log;
+import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
@@ -30,6 +33,8 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import kotlinx.coroutines.CoroutineScope;
+
/**
* Base class for a condition that needs to be fulfilled in order for {@link Monitor} to inform
* its callbacks.
@@ -39,24 +44,27 @@ public abstract class Condition {
private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();
private final boolean mOverriding;
+ private final CoroutineScope mScope;
private Boolean mIsConditionMet;
private boolean mStarted = false;
/**
* By default, conditions have an initial value of false and are not overriding.
*/
- public Condition() {
- this(false, false);
+ public Condition(CoroutineScope scope) {
+ this(scope, false, false);
}
/**
* Constructor for specifying initial state and overriding condition attribute.
+ *
* @param initialConditionMet Initial state of the condition.
- * @param overriding Whether this condition overrides others.
+ * @param overriding Whether this condition overrides others.
*/
- protected Condition(Boolean initialConditionMet, boolean overriding) {
+ protected Condition(CoroutineScope scope, Boolean initialConditionMet, boolean overriding) {
mIsConditionMet = initialConditionMet;
mOverriding = overriding;
+ mScope = scope;
}
/**
@@ -70,6 +78,29 @@ public abstract class Condition {
protected abstract void stop();
/**
+ * Condition should be started as soon as there is an active subscription.
+ */
+ public static final int START_EAGERLY = 0;
+ /**
+ * Condition should be started lazily only if needed. But once started, it will not be cancelled
+ * unless there are no more active subscriptions.
+ */
+ public static final int START_LAZILY = 1;
+ /**
+ * Condition should be started lazily only if needed, and can be stopped when not needed. This
+ * should be used for conditions which are expensive to keep running.
+ */
+ public static final int START_WHEN_NEEDED = 2;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({START_EAGERLY, START_LAZILY, START_WHEN_NEEDED})
+ @interface StartStrategy {
+ }
+
+ @StartStrategy
+ protected abstract int getStartStrategy();
+
+ /**
* Returns whether the current condition overrides
*/
public boolean isOverridingCondition() {
@@ -183,6 +214,7 @@ public abstract class Condition {
/**
* Returns whether the condition is set. This method should be consulted to understand the
* value of {@link #isConditionMet()}.
+ *
* @return {@code true} if value is present, {@code false} otherwise.
*/
public boolean isConditionSet() {
@@ -210,17 +242,18 @@ public abstract class Condition {
* conditions are true.
*/
public Condition and(@NonNull Collection<Condition> others) {
- final List<Condition> conditions = new ArrayList<>(others);
+ final List<Condition> conditions = new ArrayList<>();
conditions.add(this);
- return new CombinedCondition(conditions, Evaluator.OP_AND);
+ conditions.addAll(others);
+ return new CombinedCondition(mScope, conditions, Evaluator.OP_AND);
}
/**
* Creates a new condition which will only be true when both this condition and the provided
* condition is true.
*/
- public Condition and(@NonNull Condition other) {
- return new CombinedCondition(Arrays.asList(this, other), Evaluator.OP_AND);
+ public Condition and(@NonNull Condition... others) {
+ return and(Arrays.asList(others));
}
/**
@@ -228,17 +261,18 @@ public abstract class Condition {
* provided conditions are true.
*/
public Condition or(@NonNull Collection<Condition> others) {
- final List<Condition> conditions = new ArrayList<>(others);
+ final List<Condition> conditions = new ArrayList<>();
conditions.add(this);
- return new CombinedCondition(conditions, Evaluator.OP_OR);
+ conditions.addAll(others);
+ return new CombinedCondition(mScope, conditions, Evaluator.OP_OR);
}
/**
* Creates a new condition which will only be true when either this condition or the provided
* condition is true.
*/
- public Condition or(@NonNull Condition other) {
- return new CombinedCondition(Arrays.asList(this, other), Evaluator.OP_OR);
+ public Condition or(@NonNull Condition... others) {
+ return or(Arrays.asList(others));
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
index 8f8bff86f64d..84edc3577007 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
@@ -1,14 +1,22 @@
package com.android.systemui.shared.condition
+import com.android.systemui.shared.condition.Condition.StartStrategy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
+import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
/** Converts a boolean flow to a [Condition] object which can be used with a [Monitor] */
@JvmOverloads
-fun Flow<Boolean>.toCondition(scope: CoroutineScope, initialValue: Boolean? = null): Condition {
- return object : Condition(initialValue, false) {
+fun Flow<Boolean>.toCondition(
+ scope: CoroutineScope,
+ @StartStrategy strategy: Int,
+ initialValue: Boolean? = null
+): Condition {
+ return object : Condition(scope, initialValue, false) {
var job: Job? = null
override fun start() {
@@ -19,5 +27,25 @@ fun Flow<Boolean>.toCondition(scope: CoroutineScope, initialValue: Boolean? = nu
job?.cancel()
job = null
}
+
+ override fun getStartStrategy() = strategy
}
}
+
+/** Converts a [Condition] to a boolean flow */
+fun Condition.toFlow(): Flow<Boolean?> {
+ return callbackFlow {
+ val callback =
+ Condition.Callback { condition ->
+ if (condition.isConditionSet) {
+ trySend(condition.isConditionMet)
+ } else {
+ trySend(null)
+ }
+ }
+ addCallback(callback)
+ callback.onConditionChanged(this@toFlow)
+ awaitClose { removeCallback(callback) }
+ }
+ .distinctUntilChanged()
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt
index 454294f36d2a..584d9785c300 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt
@@ -22,7 +22,7 @@ import android.annotation.IntDef
* Helper for evaluating a collection of [Condition] objects with a given
* [Evaluator.ConditionOperand]
*/
-internal object Evaluator {
+object Evaluator {
/** Operands for combining multiple conditions together */
@Retention(AnnotationRetention.SOURCE)
@IntDef(value = [OP_AND, OP_OR])
@@ -70,15 +70,31 @@ internal object Evaluator {
fun evaluate(conditions: Collection<Condition>, @ConditionOperand operand: Int): Boolean? {
if (conditions.isEmpty()) return null
// If there are overriding conditions with values set, they take precedence.
- val targetConditions =
+ val values: Collection<Boolean?> =
conditions
.filter { it.isConditionSet && it.isOverridingCondition }
.ifEmpty { conditions }
+ .map { condition ->
+ if (condition.isConditionSet) {
+ condition.isConditionMet
+ } else {
+ null
+ }
+ }
+ return evaluate(values = values, operand = operand)
+ }
+
+ /**
+ * Evaluates a set of booleans with a given operand
+ *
+ * @param operand The operand to use when evaluating.
+ * @return Either true or false if the value is known, or null if value is unknown
+ */
+ internal fun evaluate(values: Collection<Boolean?>, @ConditionOperand operand: Int): Boolean? {
+ if (values.isEmpty()) return null
return when (operand) {
- OP_AND ->
- threeValuedAndOrOr(conditions = targetConditions, returnValueIfAnyMatches = false)
- OP_OR ->
- threeValuedAndOrOr(conditions = targetConditions, returnValueIfAnyMatches = true)
+ OP_AND -> threeValuedAndOrOr(values = values, returnValueIfAnyMatches = false)
+ OP_OR -> threeValuedAndOrOr(values = values, returnValueIfAnyMatches = true)
else -> null
}
}
@@ -90,16 +106,16 @@ internal object Evaluator {
* any value is true.
*/
private fun threeValuedAndOrOr(
- conditions: Collection<Condition>,
+ values: Collection<Boolean?>,
returnValueIfAnyMatches: Boolean
): Boolean? {
var hasUnknown = false
- for (condition in conditions) {
- if (!condition.isConditionSet) {
+ for (value in values) {
+ if (value == null) {
hasUnknown = true
continue
}
- if (condition.isConditionMet == returnValueIfAnyMatches) {
+ if (value == returnValueIfAnyMatches) {
return returnValueIfAnyMatches
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
index 016d573930e8..4a665621b3fe 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
@@ -230,7 +230,7 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager
private ClassLoader getParentClassLoader(ClassLoader baseClassLoader) {
return new PluginManagerImpl.ClassLoaderFilter(
- baseClassLoader, "com.android.systemui.plugin");
+ baseClassLoader, "com.android.systemui.log", "com.android.systemui.plugin");
}
/** Returns class loader specific for the given plugin. */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index 2f9f5b2ac938..1e668b84cdc6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -248,19 +248,23 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
// This allows plugins to include any libraries or copied code they want by only including
// classes from the plugin library.
static class ClassLoaderFilter extends ClassLoader {
- private final String mPackage;
+ private final String[] mPackages;
private final ClassLoader mBase;
- public ClassLoaderFilter(ClassLoader base, String pkg) {
+ ClassLoaderFilter(ClassLoader base, String... pkgs) {
super(ClassLoader.getSystemClassLoader());
mBase = base;
- mPackage = pkg;
+ mPackages = pkgs;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- if (!name.startsWith(mPackage)) super.loadClass(name, resolve);
- return mBase.loadClass(name);
+ for (String pkg : mPackages) {
+ if (name.startsWith(pkg)) {
+ return mBase.loadClass(name);
+ }
+ }
+ return super.loadClass(name, resolve);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
index 62f4f2282e66..a82f0e3e2a25 100644
--- a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
@@ -26,8 +26,8 @@ import android.content.res.TypedArray
import android.graphics.Color
import android.util.AttributeSet
import android.view.View
+import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
-import com.android.systemui.animation.Interpolators
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.TITLE
/** Displays security messages for the keyguard bouncer. */
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 8b87e2a538ca..4bf7be6df5be 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -42,14 +42,14 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.dagger.KeyguardLargeClockLog
import com.android.systemui.log.dagger.KeyguardSmallClockLog
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockTickRate
import com.android.systemui.plugins.WeatherData
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
import com.android.systemui.shared.regionsampling.RegionSampler
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardBouncerMessages.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardBouncerMessages.kt
new file mode 100644
index 000000000000..f4145dbef80f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardBouncerMessages.kt
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.annotation.IntDef
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_FACE_LOCKED_OUT
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_FINGERPRINT_LOCKED_OUT
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_FACE_INPUT
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST
+import com.android.systemui.R.string.bouncer_face_not_recognized
+import com.android.systemui.R.string.keyguard_enter_password
+import com.android.systemui.R.string.keyguard_enter_pattern
+import com.android.systemui.R.string.keyguard_enter_pin
+import com.android.systemui.R.string.kg_bio_too_many_attempts_password
+import com.android.systemui.R.string.kg_bio_too_many_attempts_pattern
+import com.android.systemui.R.string.kg_bio_too_many_attempts_pin
+import com.android.systemui.R.string.kg_bio_try_again_or_password
+import com.android.systemui.R.string.kg_bio_try_again_or_pattern
+import com.android.systemui.R.string.kg_bio_try_again_or_pin
+import com.android.systemui.R.string.kg_face_locked_out
+import com.android.systemui.R.string.kg_fp_locked_out
+import com.android.systemui.R.string.kg_fp_not_recognized
+import com.android.systemui.R.string.kg_primary_auth_locked_out_password
+import com.android.systemui.R.string.kg_primary_auth_locked_out_pattern
+import com.android.systemui.R.string.kg_primary_auth_locked_out_pin
+import com.android.systemui.R.string.kg_prompt_after_dpm_lock
+import com.android.systemui.R.string.kg_prompt_after_user_lockdown_password
+import com.android.systemui.R.string.kg_prompt_after_user_lockdown_pattern
+import com.android.systemui.R.string.kg_prompt_after_user_lockdown_pin
+import com.android.systemui.R.string.kg_prompt_auth_timeout
+import com.android.systemui.R.string.kg_prompt_password_auth_timeout
+import com.android.systemui.R.string.kg_prompt_pattern_auth_timeout
+import com.android.systemui.R.string.kg_prompt_pin_auth_timeout
+import com.android.systemui.R.string.kg_prompt_reason_restart_password
+import com.android.systemui.R.string.kg_prompt_reason_restart_pattern
+import com.android.systemui.R.string.kg_prompt_reason_restart_pin
+import com.android.systemui.R.string.kg_prompt_unattended_update
+import com.android.systemui.R.string.kg_too_many_failed_attempts_countdown
+import com.android.systemui.R.string.kg_trust_agent_disabled
+import com.android.systemui.R.string.kg_unlock_with_password_or_fp
+import com.android.systemui.R.string.kg_unlock_with_pattern_or_fp
+import com.android.systemui.R.string.kg_unlock_with_pin_or_fp
+import com.android.systemui.R.string.kg_wrong_input_try_fp_suggestion
+import com.android.systemui.R.string.kg_wrong_password_try_again
+import com.android.systemui.R.string.kg_wrong_pattern_try_again
+import com.android.systemui.R.string.kg_wrong_pin_try_again
+
+typealias BouncerMessage = Pair<Int, Int>
+
+fun emptyBouncerMessage(): BouncerMessage = Pair(0, 0)
+
+@Retention(AnnotationRetention.SOURCE)
+@IntDef(
+ PROMPT_REASON_TIMEOUT,
+ PROMPT_REASON_DEVICE_ADMIN,
+ PROMPT_REASON_USER_REQUEST,
+ PROMPT_REASON_AFTER_LOCKOUT,
+ PROMPT_REASON_PREPARE_FOR_UPDATE,
+ PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT,
+ PROMPT_REASON_TRUSTAGENT_EXPIRED,
+ PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
+ PROMPT_REASON_INCORRECT_FACE_INPUT,
+ PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT,
+ PROMPT_REASON_FACE_LOCKED_OUT,
+ PROMPT_REASON_FINGERPRINT_LOCKED_OUT,
+ PROMPT_REASON_DEFAULT,
+ PROMPT_REASON_NONE,
+ PROMPT_REASON_RESTART,
+ PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT,
+)
+annotation class BouncerPromptReason
+
+/**
+ * Helper method that provides the relevant bouncer message that should be shown for different
+ * scenarios indicated by [reason]. [securityMode] & [fpAllowedInBouncer] parameters are used to
+ * provide a more specific message.
+ */
+@JvmOverloads
+fun getBouncerMessage(
+ @BouncerPromptReason reason: Int,
+ securityMode: SecurityMode,
+ fpAllowedInBouncer: Boolean = false
+): BouncerMessage {
+ return when (reason) {
+ PROMPT_REASON_RESTART -> authRequiredAfterReboot(securityMode)
+ PROMPT_REASON_TIMEOUT -> authRequiredAfterPrimaryAuthTimeout(securityMode)
+ PROMPT_REASON_DEVICE_ADMIN -> authRequiredAfterAdminLockdown(securityMode)
+ PROMPT_REASON_USER_REQUEST -> authRequiredAfterUserLockdown(securityMode)
+ PROMPT_REASON_AFTER_LOCKOUT -> biometricLockout(securityMode)
+ PROMPT_REASON_PREPARE_FOR_UPDATE -> authRequiredForUnattendedUpdate(securityMode)
+ PROMPT_REASON_FINGERPRINT_LOCKED_OUT -> fingerprintUnlockUnavailable(securityMode)
+ PROMPT_REASON_FACE_LOCKED_OUT -> faceUnlockUnavailable(securityMode)
+ PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT ->
+ if (fpAllowedInBouncer) incorrectSecurityInputWithFingerprint(securityMode)
+ else incorrectSecurityInput(securityMode)
+ PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT ->
+ if (fpAllowedInBouncer) nonStrongAuthTimeoutWithFingerprintAllowed(securityMode)
+ else nonStrongAuthTimeout(securityMode)
+ PROMPT_REASON_TRUSTAGENT_EXPIRED ->
+ if (fpAllowedInBouncer) trustAgentDisabledWithFingerprintAllowed(securityMode)
+ else trustAgentDisabled(securityMode)
+ PROMPT_REASON_INCORRECT_FACE_INPUT ->
+ if (fpAllowedInBouncer) incorrectFaceInputWithFingerprintAllowed(securityMode)
+ else incorrectFaceInput(securityMode)
+ PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT -> incorrectFingerprintInput(securityMode)
+ PROMPT_REASON_DEFAULT ->
+ if (fpAllowedInBouncer) defaultMessageWithFingerprint(securityMode)
+ else defaultMessage(securityMode)
+ PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT -> primaryAuthLockedOut(securityMode)
+ else -> emptyBouncerMessage()
+ }
+}
+
+fun defaultMessage(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, 0)
+ SecurityMode.Password -> Pair(keyguard_enter_password, 0)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, 0)
+ else -> Pair(0, 0)
+ }
+}
+
+fun defaultMessageWithFingerprint(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, 0)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, 0)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, 0)
+ else -> Pair(0, 0)
+ }
+}
+
+fun incorrectSecurityInput(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, 0)
+ SecurityMode.Password -> Pair(kg_wrong_password_try_again, 0)
+ SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, 0)
+ else -> Pair(0, 0)
+ }
+}
+
+fun incorrectSecurityInputWithFingerprint(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, kg_wrong_input_try_fp_suggestion)
+ SecurityMode.Password -> Pair(kg_wrong_password_try_again, kg_wrong_input_try_fp_suggestion)
+ SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, kg_wrong_input_try_fp_suggestion)
+ else -> Pair(0, 0)
+ }
+}
+
+fun incorrectFingerprintInput(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pattern)
+ SecurityMode.Password -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_password)
+ SecurityMode.PIN -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pin)
+ else -> Pair(0, 0)
+ }
+}
+
+fun incorrectFaceInput(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pattern)
+ SecurityMode.Password -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_password)
+ SecurityMode.PIN -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pin)
+ else -> Pair(0, 0)
+ }
+}
+
+fun incorrectFaceInputWithFingerprintAllowed(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, bouncer_face_not_recognized)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, bouncer_face_not_recognized)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, bouncer_face_not_recognized)
+ else -> Pair(0, 0)
+ }
+}
+
+fun biometricLockout(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_bio_too_many_attempts_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_bio_too_many_attempts_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_bio_too_many_attempts_pin)
+ else -> Pair(0, 0)
+ }
+}
+
+fun authRequiredAfterReboot(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_reason_restart_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_reason_restart_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin)
+ else -> Pair(0, 0)
+ }
+}
+
+fun authRequiredAfterAdminLockdown(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_dpm_lock)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_dpm_lock)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock)
+ else -> Pair(0, 0)
+ }
+}
+
+fun authRequiredAfterUserLockdown(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_user_lockdown_pattern)
+ SecurityMode.Password ->
+ Pair(keyguard_enter_password, kg_prompt_after_user_lockdown_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin)
+ else -> Pair(0, 0)
+ }
+}
+
+fun authRequiredForUnattendedUpdate(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_unattended_update)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_unattended_update)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_unattended_update)
+ else -> Pair(0, 0)
+ }
+}
+
+fun authRequiredAfterPrimaryAuthTimeout(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_pattern_auth_timeout)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_password_auth_timeout)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout)
+ else -> Pair(0, 0)
+ }
+}
+
+fun nonStrongAuthTimeout(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_auth_timeout)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_auth_timeout)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_auth_timeout)
+ else -> Pair(0, 0)
+ }
+}
+
+fun nonStrongAuthTimeoutWithFingerprintAllowed(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_prompt_auth_timeout)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_prompt_auth_timeout)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_prompt_auth_timeout)
+ else -> Pair(0, 0)
+ }
+}
+
+fun faceUnlockUnavailable(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_face_locked_out)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_face_locked_out)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_face_locked_out)
+ else -> Pair(0, 0)
+ }
+}
+
+fun fingerprintUnlockUnavailable(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_fp_locked_out)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_fp_locked_out)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_fp_locked_out)
+ else -> Pair(0, 0)
+ }
+}
+
+fun trustAgentDisabled(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_trust_agent_disabled)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_trust_agent_disabled)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_trust_agent_disabled)
+ else -> Pair(0, 0)
+ }
+}
+
+fun trustAgentDisabledWithFingerprintAllowed(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_trust_agent_disabled)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_trust_agent_disabled)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_trust_agent_disabled)
+ else -> Pair(0, 0)
+ }
+}
+
+fun primaryAuthLockedOut(securityMode: SecurityMode): BouncerMessage {
+ return when (securityMode) {
+ SecurityMode.Pattern ->
+ Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pattern)
+ SecurityMode.Password ->
+ Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_password)
+ SecurityMode.PIN ->
+ Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pin)
+ else -> Pair(0, 0)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index a6c782d88e18..644a9bcdd588 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -15,12 +15,13 @@ import android.widget.RelativeLayout;
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
+import com.android.systemui.log.LogBuffer;
+import com.android.systemui.log.LogLevel;
import com.android.systemui.plugins.ClockController;
-import com.android.systemui.plugins.log.LogBuffer;
-import com.android.systemui.plugins.log.LogLevel;
+import com.android.systemui.shared.clocks.DefaultClockController;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -46,6 +47,9 @@ public class KeyguardClockSwitch extends RelativeLayout {
public static final int LARGE = 0;
public static final int SMALL = 1;
+ // compensate for translation of parents subject to device screen
+ // In this case, the translation comes from KeyguardStatusView
+ public int screenOffsetYPadding = 0;
/** Returns a region for the large clock to position itself, based on the given parent. */
public static Rect getLargeClockRegion(ViewGroup parent) {
@@ -161,8 +165,18 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
if (mLargeClockFrame.isLaidOut()) {
- mClock.getLargeClock().getEvents().onTargetRegionChanged(
- getLargeClockRegion(mLargeClockFrame));
+ Rect targetRegion = getLargeClockRegion(mLargeClockFrame);
+ if (mClock instanceof DefaultClockController) {
+ mClock.getLargeClock().getEvents().onTargetRegionChanged(
+ targetRegion);
+ } else {
+ mClock.getLargeClock().getEvents().onTargetRegionChanged(
+ new Rect(
+ targetRegion.left,
+ targetRegion.top - screenOffsetYPadding,
+ targetRegion.right,
+ targetRegion.bottom - screenOffsetYPadding));
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index a34c9fa5aced..d8bf570954df 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -39,10 +39,10 @@ import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.log.LogBuffer;
+import com.android.systemui.log.LogLevel;
import com.android.systemui.log.dagger.KeyguardClockLog;
import com.android.systemui.plugins.ClockController;
-import com.android.systemui.plugins.log.LogBuffer;
-import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.shared.regionsampling.RegionSampler;
@@ -169,6 +169,16 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
/**
+ * Used for status view to pass the screen offset from parent view
+ */
+ public void setLockscreenClockY(int clockY) {
+ if (mView.screenOffsetYPadding != clockY) {
+ mView.screenOffsetYPadding = clockY;
+ mView.updateClockTargetRegions();
+ }
+ }
+
+ /**
* Attach the controller to the view it relates to.
*/
@Override
@@ -394,13 +404,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
PropertyAnimator.setProperty(mStatusArea, AnimatableProperty.TRANSLATION_X,
x, props, animate);
}
-
- }
-
- void updateKeyguardStatusViewOffset() {
- // updateClockTargetRegions will call onTargetRegionChanged
- // which will require the correct translationY property of keyguardStatusView after updating
- mView.updateClockTargetRegions();
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 03947542d21e..58807e4bf3bd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_APPEAR;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
@@ -32,9 +33,9 @@ import android.view.animation.Interpolator;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
/**
@@ -184,6 +185,7 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
}
mAppearAnimator.setDuration(ANIMATION_DURATION);
mAppearAnimator.addUpdateListener(animation -> animate(animation.getAnimatedFraction()));
+ mAppearAnimator.addListener(getAnimationListener(CUJ_LOCKSCREEN_PIN_APPEAR));
mAppearAnimator.start();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 33bea027cd20..1d7c35d0c90d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -45,11 +45,11 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.systemui.DejankUtils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
/**
* Displays an alphanumeric (latin-1) key entry for the user to enter
* an unlock password
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 0a91150e6c39..b4ddc9a975c2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -34,9 +34,9 @@ import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.internal.widget.LockscreenCredential;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b88d85c843e4..5cc0547b5bde 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -32,7 +32,7 @@ import static androidx.constraintlayout.widget.ConstraintSet.START;
import static androidx.constraintlayout.widget.ConstraintSet.TOP;
import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
-import static com.android.systemui.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
+import static com.android.app.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
import static java.lang.Integer.max;
@@ -87,6 +87,7 @@ import androidx.constraintlayout.widget.ConstraintSet;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
+import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -97,7 +98,6 @@ import com.android.settingslib.Utils;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 22ad725faaa2..419303d71f97 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -67,6 +67,42 @@ public interface KeyguardSecurityView {
int PROMPT_REASON_TRUSTAGENT_EXPIRED = 8;
/**
+ * Prompt that is shown when there is an incorrect primary authentication input.
+ */
+ int PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT = 9;
+
+ /**
+ * Prompt that is shown when there is an incorrect face biometric input.
+ */
+ int PROMPT_REASON_INCORRECT_FACE_INPUT = 10;
+
+ /**
+ * Prompt that is shown when there is an incorrect fingerprint biometric input.
+ */
+ int PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT = 11;
+
+ /**
+ * Prompt that is shown when face authentication is in locked out state.
+ */
+ int PROMPT_REASON_FACE_LOCKED_OUT = 12;
+
+ /**
+ * Prompt that is shown when fingerprint authentication is in locked out state.
+ */
+ int PROMPT_REASON_FINGERPRINT_LOCKED_OUT = 13;
+
+ /**
+ * Default prompt that is shown on the bouncer.
+ */
+ int PROMPT_REASON_DEFAULT = 14;
+
+ /**
+ * Prompt that is shown when primary authentication is in locked out state after too many
+ * attempts
+ */
+ int PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT = 15;
+
+ /**
* Reset the view and prepare to take input. This should do things like clearing the
* password or pattern and clear error messages.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
index c9128e5881cc..96ac8ad56651 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
@@ -26,9 +26,9 @@ import android.util.MathUtils
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
+import com.android.app.animation.Interpolators
import com.android.internal.R.interpolator.fast_out_extra_slow_in
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
/** Animates constraint layout changes for the security view. */
class KeyguardSecurityViewTransition : Transition() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 65a71664e245..b4f124aa598a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -44,11 +44,11 @@ import androidx.slice.core.SliceQuery;
import androidx.slice.widget.RowContent;
import androidx.slice.widget.SliceContent;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 0826f8a8b985..794eeda86b0f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -40,11 +40,11 @@ import androidx.annotation.VisibleForTesting;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
+import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ClockController;
@@ -215,6 +215,15 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
/**
+ * Pass top margin from ClockPositionAlgorithm in NotificationPanelViewController
+ * Use for clock view in LS to compensate for top margin to align to the screen
+ * Regardless of translation from AOD and unlock gestures
+ */
+ public void setLockscreenClockY(int clockY) {
+ mKeyguardClockSwitchController.setLockscreenClockY(clockY);
+ }
+
+ /**
* Set whether the view accessibility importance mode.
*/
public void setStatusAccessibilityImportance(int mode) {
@@ -230,7 +239,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
* Update position of the view with an optional animation
*/
public void updatePosition(int x, int y, float scale, boolean animate) {
- float oldY = mView.getY();
setProperty(AnimatableProperty.Y, y, animate);
ClockController clock = mKeyguardClockSwitchController.getClock();
@@ -246,10 +254,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
setProperty(AnimatableProperty.SCALE_X, 1f, animate);
setProperty(AnimatableProperty.SCALE_Y, 1f, animate);
}
-
- if (oldY != y) {
- mKeyguardClockSwitchController.updateKeyguardStatusViewOffset();
- }
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9573913e5e2f..7d7b276fbe44 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -522,6 +522,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
FACE_AUTH_TRIGGERED_TRUST_DISABLED);
}
+ mLogger.logTrustChanged(wasTrusted, enabled, userId);
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onTrustChanged(userId);
+ }
+ }
+
if (enabled) {
String message = null;
if (KeyguardUpdateMonitor.getCurrentUser() == userId
@@ -560,14 +568,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
}
-
- mLogger.logTrustChanged(wasTrusted, enabled, userId);
- for (int i = 0; i < mCallbacks.size(); i++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
- if (cb != null) {
- cb.onTrustChanged(userId);
- }
- }
}
/**
@@ -4379,9 +4379,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
*/
public void startBiometricWatchdog() {
if (mFaceManager != null && !isFaceAuthInteractorEnabled()) {
+ mLogger.scheduleWatchdog("face");
mFaceManager.scheduleWatchdog();
}
if (mFpm != null) {
+ mLogger.scheduleWatchdog("fingerprint");
mFpm.scheduleWatchdog();
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index 651c9796140e..61af7228fe0d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -21,9 +21,9 @@ import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import android.util.Property;
import android.view.View;
-import com.android.systemui.animation.Interpolators;
-import com.android.systemui.plugins.log.LogBuffer;
-import com.android.systemui.plugins.log.LogLevel;
+import com.android.app.animation.Interpolators;
+import com.android.systemui.log.LogBuffer;
+import com.android.systemui.log.LogLevel;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index c6c7113d7f9a..7d76f12880df 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -37,7 +37,7 @@ import android.widget.TextView;
import androidx.annotation.StyleRes;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
/**
* Provides background color and radius animations for key pad buttons.
diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
index 4aeab970e2f7..4557b3418e19 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
@@ -37,9 +37,9 @@ import android.widget.LinearLayout;
import androidx.core.graphics.drawable.DrawableCompat;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
/**
* This class contains implementation for methods that will be used when user has set a
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
index 6740375c4329..2d0bf9cc2aba 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
@@ -27,9 +27,9 @@ import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.dagger.KeyguardClockLog;
import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.shared.clocks.DefaultClockProvider;
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
index 2bb75aa34c6a..e7295ef9052c 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
@@ -17,9 +17,9 @@
package com.android.keyguard.logging
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.dagger.BiometricLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
import javax.inject.Inject
/** Helper class for logging for [com.android.systemui.biometrics.FaceHelpMessageDeferral] */
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
index 20f90072161b..c00b2c612fa2 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
@@ -18,11 +18,11 @@ package com.android.keyguard.logging
import android.hardware.biometrics.BiometricSourceType
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.dagger.BiometricLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_DISMISS_BOUNCER
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_NONE
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_ONLY_WAKE
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index 4d71a8952021..8b925b1bfb54 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -18,9 +18,9 @@ package com.android.keyguard.logging
import com.android.systemui.biometrics.AuthRippleController
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.KeyguardLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.KeyguardIndicationController
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 16618064f249..c2d22c3e1d14 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -27,13 +27,13 @@ import com.android.keyguard.KeyguardListenModel
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.TrustGrantFlags
import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.ERROR
-import com.android.systemui.plugins.log.LogLevel.INFO
-import com.android.systemui.plugins.log.LogLevel.VERBOSE
-import com.android.systemui.plugins.log.LogLevel.WARNING
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.ERROR
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.LogLevel.VERBOSE
+import com.android.systemui.log.LogLevel.WARNING
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
@@ -67,8 +67,10 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) {
"ActiveUnlock",
DEBUG,
{ int1 = wakeReason },
- { "Skip requesting active unlock from wake reason that doesn't trigger face auth" +
- " reason=${PowerManager.wakeReasonToString(int1)}" }
+ {
+ "Skip requesting active unlock from wake reason that doesn't trigger face auth" +
+ " reason=${PowerManager.wakeReasonToString(int1)}"
+ }
)
}
@@ -207,17 +209,27 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) {
}
fun logFaceDetected(userId: Int, isStrongBiometric: Boolean) {
- logBuffer.log(TAG, DEBUG, {
- int1 = userId
- bool1 = isStrongBiometric
- }, {"Face detected: userId: $int1, isStrongBiometric: $bool1"})
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = userId
+ bool1 = isStrongBiometric
+ },
+ { "Face detected: userId: $int1, isStrongBiometric: $bool1" }
+ )
}
fun logFingerprintDetected(userId: Int, isStrongBiometric: Boolean) {
- logBuffer.log(TAG, DEBUG, {
- int1 = userId
- bool1 = isStrongBiometric
- }, {"Fingerprint detected: userId: $int1, isStrongBiometric: $bool1"})
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = userId
+ bool1 = isStrongBiometric
+ },
+ { "Fingerprint detected: userId: $int1, isStrongBiometric: $bool1" }
+ )
}
fun logFingerprintError(msgId: Int, originalErrMsg: String) {
@@ -669,13 +681,10 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) {
}
fun logHandleBatteryUpdate(isInteresting: Boolean) {
- logBuffer.log(
- TAG,
- DEBUG,
- {
- bool1 = isInteresting
- },
- { "handleBatteryUpdate: $bool1" }
- )
+ logBuffer.log(TAG, DEBUG, { bool1 = isInteresting }, { "handleBatteryUpdate: $bool1" })
+ }
+
+ fun scheduleWatchdog(@CompileTimeConstant watchdogType: String) {
+ logBuffer.log(TAG, DEBUG, "Scheduling biometric watchdog for $watchdogType")
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt
index 249b3fe97d81..daafea8b62c7 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt
@@ -18,9 +18,9 @@ package com.android.keyguard.logging
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.TrustModel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** Logging helper for trust repository. */
diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
index de82ca014722..c1871e09a791 100644
--- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
+++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
@@ -36,7 +36,7 @@ import android.view.Surface
import android.view.View
import androidx.annotation.VisibleForTesting
import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.util.asIndenting
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
index a3e7d71a92f6..76086dffd263 100644
--- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
@@ -34,7 +34,7 @@ import androidx.core.graphics.ColorUtils
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.settingslib.Utils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.biometrics.AuthController
import com.android.systemui.log.ScreenDecorationsLogger
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -110,6 +110,10 @@ class FaceScanningOverlay(
if (showScanningAnimNow == showScanningAnim) {
return
}
+ logger.cameraProtectionShownOrHidden(keyguardUpdateMonitor.isFaceDetectionRunning,
+ authController.isShowing,
+ show,
+ showScanningAnim)
showScanningAnim = showScanningAnimNow
updateProtectionBoundingPath()
// Delay the relayout until the end of the animation when hiding,
@@ -352,6 +356,7 @@ class FaceScanningOverlay(
if (biometricSourceType == BiometricSourceType.FACE) {
post {
faceAuthSucceeded = true
+ logger.biometricEvent("biometricAuthenticated")
enableShowProtection(true)
}
}
@@ -372,6 +377,7 @@ class FaceScanningOverlay(
if (biometricSourceType == BiometricSourceType.FACE) {
post {
faceAuthSucceeded = false
+ logger.biometricEvent("biometricFailed")
enableShowProtection(false)
}
}
@@ -385,6 +391,7 @@ class FaceScanningOverlay(
if (biometricSourceType == BiometricSourceType.FACE) {
post {
faceAuthSucceeded = false
+ logger.biometricEvent("biometricError")
enableShowProtection(false)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index adc04128a93a..ea0f343e80f4 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -90,6 +90,8 @@ import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.ThreadFactory;
import com.android.systemui.util.settings.SecureSettings;
+import kotlin.Pair;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -98,8 +100,6 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
-import kotlin.Pair;
-
/**
* An overlay that draws screen decorations in software (e.g for rounded corners or display cutout)
* for antialiasing and emulation purposes.
@@ -254,11 +254,13 @@ public class ScreenDecorations implements CoreStartable, Tunable , Dumpable {
new CameraAvailabilityListener.CameraTransitionCallback() {
@Override
public void onApplyCameraProtection(@NonNull Path protectionPath, @NonNull Rect bounds) {
+ mLogger.cameraProtectionEvent("onApplyCameraProtection");
showCameraProtection(protectionPath, bounds);
}
@Override
public void onHideCameraProtection() {
+ mLogger.cameraProtectionEvent("onHideCameraProtection");
hideCameraProtection();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index aa94ad98f3e6..99d46629ad7a 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -43,8 +43,8 @@ import android.view.accessibility.AccessibilityEvent;
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.internal.dynamicanimation.animation.SpringForce;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.FalsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index d6f0b59accb1..d49197557dc4 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -32,8 +32,8 @@ import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
/**
* Visually discloses that contextual data was provided to an assistant.
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 0002ae95f476..2aac056b0bde 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -45,9 +45,9 @@ import android.widget.TextView;
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.systemui.DualToneHandler;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.BatteryController;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index b386bc9d050b..ce85124fa7a7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -59,11 +59,11 @@ import android.widget.ScrollView;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.biometrics.AuthController.ScaleFactorProvider;
import com.android.systemui.biometrics.domain.interactor.BiometricPromptCredentialInteractor;
import com.android.systemui.biometrics.ui.CredentialView;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 3579e8cc0218..fd9cee0d6144 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -829,9 +829,9 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
final Rect overlayBounds = new Rect(
0, /* left */
- 0, /* top */
+ mCachedDisplayInfo.getNaturalHeight() / 2, /* top */
mCachedDisplayInfo.getNaturalWidth(), /* right */
- mCachedDisplayInfo.getNaturalHeight() /* botom */);
+ mCachedDisplayInfo.getNaturalHeight() /* bottom */);
mUdfpsOverlayParams = new UdfpsOverlayParams(
mUdfpsBounds,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index d0ac2968ae8e..6f0f6331ef50 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -32,12 +32,12 @@ import com.android.settingslib.Utils
import com.android.settingslib.udfps.UdfpsOverlayParams
import com.android.systemui.CoreStartable
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogLevel
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.CircleReveal
import com.android.systemui.statusbar.LiftReveal
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index b0071340cf1a..5ede16d221b7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -28,7 +28,7 @@ import android.util.AttributeSet
import android.view.View
import android.view.animation.PathInterpolator
import com.android.internal.graphics.ColorUtils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.surfaceeffects.ripple.RippleShader
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
index ef7dcb7aac93..1dbafc6519f0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -19,7 +19,7 @@ import android.animation.ValueAnimator
import android.graphics.PointF
import android.graphics.RectF
import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionListener
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index f876affb2a9c..d953a885fe1f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -364,7 +364,12 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
if (accessibilityManager.isTouchExplorationEnabled && isEnrollment) {
Rect(overlayParams.sensorBounds)
} else {
- Rect(overlayParams.overlayBounds)
+ Rect(
+ 0,
+ 0,
+ overlayParams.naturalDisplayWidth,
+ overlayParams.naturalDisplayHeight
+ )
}
} else {
Rect(overlayParams.sensorBounds)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index ba8e60a08a1d..52db4ab8b593 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -40,9 +40,9 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieProperty;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index 935de0255c01..9f5669f91280 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -23,11 +23,11 @@ import android.view.MotionEvent
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.animation.Interpolators
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
index 0d08b4307f12..39199d194cc9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
@@ -16,12 +16,12 @@
package com.android.systemui.biometrics
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogLevel.ERROR
+import com.android.systemui.log.LogLevel.VERBOSE
+import com.android.systemui.log.LogLevel.WARNING
import com.android.systemui.log.dagger.UdfpsLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogLevel.ERROR
-import com.android.systemui.plugins.log.LogLevel.VERBOSE
-import com.android.systemui.plugins.log.LogLevel.WARNING
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
index e2d36dc6abe1..9292bd7ecd60 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
@@ -6,8 +6,8 @@ import android.widget.ImageView
import android.widget.TextView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.biometrics.AuthDialog
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.ui.CredentialPasswordView
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
index d99625a9fbf2..96af42bfda22 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.bluetooth
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.BluetoothLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** Helper class for logging bluetooth events. */
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt b/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
index d27708fc04d7..5b3a982ab5e2 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
@@ -20,11 +20,11 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.INFO
-import com.android.systemui.plugins.log.LogMessage
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.LogMessage
import com.android.systemui.log.dagger.BroadcastDispatcherLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 11ef749573b7..7bf8f4dac1fb 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -30,9 +30,9 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.surfaceeffects.ripple.RippleShader;
import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape;
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt
new file mode 100644
index 000000000000..0542e13ba6da
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.clipboardoverlay
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.net.Uri
+import android.util.Log
+import android.util.Size
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import java.io.IOException
+import java.util.function.Consumer
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import kotlinx.coroutines.withTimeoutOrNull
+
+class ClipboardImageLoader
+@Inject
+constructor(
+ private val context: Context,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ @Application private val mainScope: CoroutineScope
+) {
+ private val TAG: String = "ClipboardImageLoader"
+
+ suspend fun load(uri: Uri, timeoutMs: Long = 300) =
+ withTimeoutOrNull(timeoutMs) {
+ withContext(bgDispatcher) {
+ try {
+ val size = context.resources.getDimensionPixelSize(R.dimen.overlay_x_scale)
+ context.contentResolver.loadThumbnail(uri, Size(size, size * 4), null)
+ } catch (e: IOException) {
+ Log.e(TAG, "Thumbnail loading failed!", e)
+ null
+ }
+ }
+ }
+
+ fun loadAsync(uri: Uri, callback: Consumer<Bitmap?>) {
+ mainScope.launch { callback.accept(load(uri)) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 0aeab10101f6..757ebf45e9ad 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -32,6 +32,7 @@ import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBO
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TAP_OUTSIDE;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT;
+import static com.android.systemui.flags.Flags.CLIPBOARD_IMAGE_TIMEOUT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -90,6 +91,7 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
private final ClipboardOverlayUtils mClipboardUtils;
private final FeatureFlags mFeatureFlags;
private final Executor mBgExecutor;
+ private final ClipboardImageLoader mClipboardImageLoader;
private final ClipboardOverlayView mView;
@@ -109,6 +111,7 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
private Runnable mOnUiUpdate;
+ private boolean mShowingUi;
private boolean mIsMinimized;
private ClipboardModel mClipboardModel;
@@ -175,9 +178,11 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
FeatureFlags featureFlags,
ClipboardOverlayUtils clipboardUtils,
@Background Executor bgExecutor,
+ ClipboardImageLoader clipboardImageLoader,
UiEventLogger uiEventLogger) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
+ mClipboardImageLoader = clipboardImageLoader;
mClipboardLogger = new ClipboardLogger(uiEventLogger);
@@ -260,21 +265,42 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
boolean shouldAnimate = !model.dataMatches(mClipboardModel) || wasExiting;
mClipboardModel = model;
mClipboardLogger.setClipSource(mClipboardModel.getSource());
- if (shouldAnimate) {
- reset();
- mClipboardLogger.setClipSource(mClipboardModel.getSource());
- if (shouldShowMinimized(mWindow.getWindowInsets())) {
- mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_MINIMIZED);
- mIsMinimized = true;
- mView.setMinimized(true);
- } else {
- mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_EXPANDED);
+ if (mFeatureFlags.isEnabled(CLIPBOARD_IMAGE_TIMEOUT)) {
+ if (shouldAnimate) {
+ reset();
+ mClipboardLogger.setClipSource(mClipboardModel.getSource());
+ if (shouldShowMinimized(mWindow.getWindowInsets())) {
+ mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_MINIMIZED);
+ mIsMinimized = true;
+ mView.setMinimized(true);
+ } else {
+ mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_EXPANDED);
+ setExpandedView(this::animateIn);
+ }
+ mView.announceForAccessibility(
+ getAccessibilityAnnouncement(mClipboardModel.getType()));
+ } else if (!mIsMinimized) {
+ setExpandedView(() -> {
+ });
+ }
+ } else {
+ if (shouldAnimate) {
+ reset();
+ mClipboardLogger.setClipSource(mClipboardModel.getSource());
+ if (shouldShowMinimized(mWindow.getWindowInsets())) {
+ mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_MINIMIZED);
+ mIsMinimized = true;
+ mView.setMinimized(true);
+ } else {
+ mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_EXPANDED);
+ setExpandedView();
+ animateIn();
+ }
+ mView.announceForAccessibility(
+ getAccessibilityAnnouncement(mClipboardModel.getType()));
+ } else if (!mIsMinimized) {
setExpandedView();
}
- animateIn();
- mView.announceForAccessibility(getAccessibilityAnnouncement(mClipboardModel.getType()));
- } else if (!mIsMinimized) {
- setExpandedView();
}
if (mClipboardModel.isRemote()) {
mTimeoutHandler.cancelTimeout();
@@ -285,6 +311,58 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
}
}
+ private void setExpandedView(Runnable onViewReady) {
+ final ClipboardModel model = mClipboardModel;
+ mView.setMinimized(false);
+ switch (model.getType()) {
+ case TEXT:
+ if (model.isRemote() || DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
+ if (model.getTextLinks() != null) {
+ classifyText(model);
+ }
+ }
+ if (model.isSensitive()) {
+ mView.showTextPreview(mContext.getString(R.string.clipboard_asterisks), true);
+ } else {
+ mView.showTextPreview(model.getText().toString(), false);
+ }
+ mView.setEditAccessibilityAction(true);
+ mOnPreviewTapped = this::editText;
+ onViewReady.run();
+ break;
+ case IMAGE:
+ mView.setEditAccessibilityAction(true);
+ mOnPreviewTapped = () -> editImage(model.getUri());
+ if (model.isSensitive()) {
+ mView.showImagePreview(null);
+ onViewReady.run();
+ } else {
+ mClipboardImageLoader.loadAsync(model.getUri(), (bitmap) -> mView.post(() -> {
+ if (bitmap == null) {
+ mView.showDefaultTextPreview();
+ } else {
+ mView.showImagePreview(bitmap);
+ }
+ onViewReady.run();
+ }));
+ }
+ break;
+ case URI:
+ case OTHER:
+ mView.showDefaultTextPreview();
+ onViewReady.run();
+ break;
+ }
+ if (!model.isRemote()) {
+ maybeShowRemoteCopy(model.getClipData());
+ }
+ if (model.getType() != ClipboardModel.Type.OTHER) {
+ mOnShareTapped = () -> shareContent(model.getClipData());
+ mView.showShareChip();
+ }
+ }
+
private void setExpandedView() {
final ClipboardModel model = mClipboardModel;
mView.setMinimized(false);
@@ -350,8 +428,12 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_EXPANDED_FROM_MINIMIZED);
mIsMinimized = false;
}
- setExpandedView();
- animateIn();
+ if (mFeatureFlags.isEnabled(CLIPBOARD_IMAGE_TIMEOUT)) {
+ setExpandedView(() -> animateIn());
+ } else {
+ setExpandedView();
+ animateIn();
+ }
}
});
mEnterAnimator.start();
@@ -412,7 +494,8 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
mInputMonitor.getInputChannel(), Looper.getMainLooper()) {
@Override
public void onInputEvent(InputEvent event) {
- if (event instanceof MotionEvent) {
+ if ((!mFeatureFlags.isEnabled(CLIPBOARD_IMAGE_TIMEOUT) || mShowingUi)
+ && event instanceof MotionEvent) {
MotionEvent motionEvent = (MotionEvent) event;
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
if (!mView.isInTouchRegion(
@@ -452,6 +535,12 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
mEnterAnimator = mView.getEnterAnimation();
mEnterAnimator.addListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mShowingUi = true;
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (mOnUiUpdate != null) {
@@ -518,6 +607,7 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
mOnRemoteCopyTapped = null;
mOnShareTapped = null;
mOnPreviewTapped = null;
+ mShowingUi = false;
mView.reset();
mTimeoutHandler.cancelTimeout();
mClipboardLogger.reset();
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/CommonRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/CommonRepositoryModule.kt
new file mode 100644
index 000000000000..9b0c3fa7e92b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/CommonRepositoryModule.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.common.ui.data.repository
+
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface CommonRepositoryModule {
+ @Binds fun bindRepository(impl: ConfigurationRepositoryImpl): ConfigurationRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
new file mode 100644
index 000000000000..3e6ac86e2417
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.common.ui.data.repository
+
+import android.content.Context
+import android.content.res.Configuration
+import android.view.DisplayInfo
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.wrapper.DisplayUtilsWrapper
+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.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+interface ConfigurationRepository {
+ /** Called whenever ui mode, theme or configuration has changed. */
+ val onAnyConfigurationChange: Flow<Unit>
+ val scaleForResolution: Flow<Float>
+
+ fun getResolutionScale(): Float
+}
+
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class ConfigurationRepositoryImpl
+@Inject
+constructor(
+ private val configurationController: ConfigurationController,
+ private val context: Context,
+ @Application private val scope: CoroutineScope,
+ private val displayUtils: DisplayUtilsWrapper,
+) : ConfigurationRepository {
+ private val displayInfo = MutableStateFlow(DisplayInfo())
+
+ override val onAnyConfigurationChange: Flow<Unit> =
+ ConflatedCallbackFlow.conflatedCallbackFlow {
+ val callback =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onUiModeChanged() {
+ sendUpdate("ConfigurationRepository#onUiModeChanged")
+ }
+
+ override fun onThemeChanged() {
+ sendUpdate("ConfigurationRepository#onThemeChanged")
+ }
+
+ override fun onConfigChanged(newConfig: Configuration) {
+ sendUpdate("ConfigurationRepository#onConfigChanged")
+ }
+
+ fun sendUpdate(reason: String) {
+ trySendWithFailureLogging(Unit, reason)
+ }
+ }
+ configurationController.addCallback(callback)
+ awaitClose { configurationController.removeCallback(callback) }
+ }
+
+ private val configurationChange: Flow<Unit> =
+ ConflatedCallbackFlow.conflatedCallbackFlow {
+ val callback =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration) {
+ trySendWithFailureLogging(Unit, "ConfigurationRepository#onConfigChanged")
+ }
+ }
+ configurationController.addCallback(callback)
+ awaitClose { configurationController.removeCallback(callback) }
+ }
+
+ override val scaleForResolution: StateFlow<Float> =
+ configurationChange
+ .mapLatest { getResolutionScale() }
+ .distinctUntilChanged()
+ .stateIn(scope, SharingStarted.WhileSubscribed(), getResolutionScale())
+
+ override fun getResolutionScale(): Float {
+ context.display.getDisplayInfo(displayInfo.value)
+ val maxDisplayMode =
+ displayUtils.getMaximumResolutionDisplayMode(displayInfo.value.supportedModes)
+ maxDisplayMode?.let {
+ val scaleFactor =
+ displayUtils.getPhysicalPixelDisplaySizeRatio(
+ maxDisplayMode.physicalWidth,
+ maxDisplayMode.physicalHeight,
+ displayInfo.value.naturalWidth,
+ displayInfo.value.naturalHeight
+ )
+ return if (scaleFactor == Float.POSITIVE_INFINITY) 1f else scaleFactor
+ }
+ return 1f
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
index 8d0edf829416..b447d66c08dd 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
@@ -32,7 +32,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.controls.ui.ControlsUiController
object ControlsAnimations {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 6a9aaf865251..e6361f46c8ad 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -50,7 +50,7 @@ import androidx.annotation.ColorInt
import androidx.annotation.VisibleForTesting
import com.android.internal.graphics.ColorUtils
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.util.concurrency.DelayableExecutor
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index fa36eee7c644..1461135d3d3b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -38,7 +38,7 @@ import android.view.ViewGroup
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL
import java.util.IllegalFormatException
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 8e6e0dd37a90..89c45d7f5e12 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -39,6 +39,7 @@ import com.android.systemui.biometrics.dagger.BiometricsModule;
import com.android.systemui.biometrics.dagger.UdfpsModule;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule;
+import com.android.systemui.common.ui.data.repository.CommonRepositoryModule;
import com.android.systemui.complication.dagger.ComplicationComponent;
import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.dagger.qualifiers.Main;
@@ -155,6 +156,7 @@ import javax.inject.Named;
ClipboardOverlayModule.class,
ClockInfoModule.class,
ClockRegistryModule.class,
+ CommonRepositoryModule.class,
ConnectivityModule.class,
CoroutinesModule.class,
DreamModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index d19c6ec01109..536978009f71 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -19,10 +19,10 @@ package com.android.systemui.doze
import android.view.Display
import com.android.systemui.doze.DozeLog.Reason
import com.android.systemui.doze.DozeLog.reasonToString
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.ERROR
-import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.ERROR
+import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.dagger.DozeLog
import com.android.systemui.statusbar.policy.DevicePostureController
import com.google.errorprone.annotations.CompileTimeConstant
diff --git a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelperWrapper.kt b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelperWrapper.kt
index d853e04fed90..10578521f182 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelperWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelperWrapper.kt
@@ -24,4 +24,8 @@ class BurnInHelperWrapper @Inject constructor() {
fun burnInOffset(amplitude: Int, xAxis: Boolean): Int {
return getBurnInOffset(amplitude, xAxis)
}
+
+ fun burnInProgressOffset(): Float {
+ return getBurnInProgressOffset()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
index eb7929095a4b..fdb765130157 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
@@ -16,9 +16,9 @@
package com.android.systemui.dreams
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.DreamLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** Logs dream-related stuff to a {@link LogBuffer}. */
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index df46e07e0911..c5e7e0d99286 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -25,8 +25,8 @@ import androidx.core.animation.doOnCancel
import androidx.core.animation.doOnEnd
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.complication.ComplicationHostViewController
import com.android.systemui.complication.ComplicationLayoutParams
import com.android.systemui.complication.ComplicationLayoutParams.POSITION_BOTTOM
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 15a32d21213f..c22019e96d74 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -33,9 +33,9 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
+import com.android.app.animation.Interpolators;
import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.complication.ComplicationHostViewController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
index 250cfeca5aa4..c889ac214cda 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
@@ -18,11 +18,14 @@ package com.android.systemui.dreams.conditions;
import com.android.internal.app.AssistUtils;
import com.android.internal.app.IVisualQueryDetectionAttentionListener;
+import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.shared.condition.Condition;
import javax.inject.Inject;
+import kotlinx.coroutines.CoroutineScope;
+
/**
* {@link AssistantAttentionCondition} provides a signal when assistant has the user's attention.
*/
@@ -58,8 +61,10 @@ public class AssistantAttentionCondition extends Condition {
@Inject
public AssistantAttentionCondition(
+ @Application CoroutineScope scope,
DreamOverlayStateController dreamOverlayStateController,
AssistUtils assistUtils) {
+ super(scope);
mDreamOverlayStateController = dreamOverlayStateController;
mAssistUtils = assistUtils;
}
@@ -75,6 +80,11 @@ public class AssistantAttentionCondition extends Condition {
mDreamOverlayStateController.removeCallback(mCallback);
}
+ @Override
+ protected int getStartStrategy() {
+ return START_EAGERLY;
+ }
+
private void enableVisualQueryDetection() {
if (mEnabled) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
index 3ef19b760826..99688bee68e0 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
@@ -19,19 +19,20 @@ import android.app.DreamManager;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.shared.condition.Condition;
import javax.inject.Inject;
+import kotlinx.coroutines.CoroutineScope;
+
/**
* {@link DreamCondition} provides a signal when a dream begins and ends.
*/
public class DreamCondition extends Condition {
private final DreamManager mDreamManager;
-
private final KeyguardUpdateMonitor mUpdateMonitor;
-
private final KeyguardUpdateMonitorCallback mUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@Override
@@ -41,7 +42,11 @@ public class DreamCondition extends Condition {
};
@Inject
- public DreamCondition(DreamManager dreamManager, KeyguardUpdateMonitor monitor) {
+ public DreamCondition(
+ @Application CoroutineScope scope,
+ DreamManager dreamManager,
+ KeyguardUpdateMonitor monitor) {
+ super(scope);
mDreamManager = dreamManager;
mUpdateMonitor = monitor;
}
@@ -56,4 +61,9 @@ public class DreamCondition extends Condition {
protected void stop() {
mUpdateMonitor.removeCallback(mUpdateCallback);
}
+
+ @Override
+ protected int getStartStrategy() {
+ return START_EAGERLY;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
index a2f65ba747ab..4b03fd334cb5 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
@@ -24,7 +24,7 @@ import com.android.systemui.R
import com.android.systemui.dump.DumpHandler.Companion.PRIORITY_ARG_CRITICAL
import com.android.systemui.dump.DumpHandler.Companion.PRIORITY_ARG_NORMAL
import com.android.systemui.dump.nano.SystemUIProtoDump
-import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.log.LogBuffer
import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager
import com.google.protobuf.nano.MessageNano
import java.io.BufferedOutputStream
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
index 7d1ffca88d9f..2d57633e47a8 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
@@ -16,12 +16,12 @@
package com.android.systemui.dump
-import android.util.ArrayMap
import com.android.systemui.Dumpable
import com.android.systemui.ProtoDumpable
import com.android.systemui.dump.nano.SystemUIProtoDump
-import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.log.LogBuffer
import java.io.PrintWriter
+import java.util.TreeMap
import javax.inject.Inject
import javax.inject.Singleton
@@ -36,8 +36,9 @@ import javax.inject.Singleton
*/
@Singleton
open class DumpManager @Inject constructor() {
- private val dumpables: MutableMap<String, RegisteredDumpable<Dumpable>> = ArrayMap()
- private val buffers: MutableMap<String, RegisteredDumpable<LogBuffer>> = ArrayMap()
+ // NOTE: Using TreeMap ensures that iteration is in a predictable & alphabetical order.
+ private val dumpables: MutableMap<String, RegisteredDumpable<Dumpable>> = TreeMap()
+ private val buffers: MutableMap<String, RegisteredDumpable<LogBuffer>> = TreeMap()
/** See [registerCriticalDumpable]. */
fun registerCriticalDumpable(module: Dumpable) {
@@ -132,7 +133,8 @@ open class DumpManager @Inject constructor() {
}
/**
- * Dumps the first dumpable or buffer whose registered name ends with [target]
+ * Dumps the alphabetically first, shortest-named dumpable or buffer whose registered name ends
+ * with [target].
*/
@Synchronized
fun dumpTarget(
@@ -141,19 +143,14 @@ open class DumpManager @Inject constructor() {
args: Array<String>,
tailLength: Int,
) {
- for (dumpable in dumpables.values) {
- if (dumpable.name.endsWith(target)) {
- dumpDumpable(dumpable, pw, args)
- return
+ sequence {
+ findBestTargetMatch(dumpables, target)?.let {
+ yield(it.name to { dumpDumpable(it, pw, args) })
}
- }
-
- for (buffer in buffers.values) {
- if (buffer.name.endsWith(target)) {
- dumpBuffer(buffer, pw, tailLength)
- return
+ findBestTargetMatch(buffers, target)?.let {
+ yield(it.name to { dumpBuffer(it, pw, tailLength) })
}
- }
+ }.sortedBy { it.first }.minByOrNull { it.first.length }?.second?.invoke()
}
@Synchronized
@@ -162,11 +159,8 @@ open class DumpManager @Inject constructor() {
protoDump: SystemUIProtoDump,
args: Array<String>
) {
- for (dumpable in dumpables.values) {
- if (dumpable.dumpable is ProtoDumpable && dumpable.name.endsWith(target)) {
- dumpProtoDumpable(dumpable.dumpable, protoDump, args)
- return
- }
+ findBestProtoTargetMatch(dumpables, target)?.let {
+ dumpProtoDumpable(it, protoDump, args)
}
}
@@ -303,6 +297,22 @@ open class DumpManager @Inject constructor() {
val existingDumpable = dumpables[name]?.dumpable ?: buffers[name]?.dumpable
return existingDumpable == null || newDumpable == existingDumpable
}
+
+ private fun <V : Any> findBestTargetMatch(map: Map<String, V>, target: String): V? = map
+ .asSequence()
+ .filter { it.key.endsWith(target) }
+ .minByOrNull { it.key.length }
+ ?.value
+
+ private fun findBestProtoTargetMatch(
+ map: Map<String, RegisteredDumpable<Dumpable>>,
+ target: String
+ ): ProtoDumpable? = map
+ .asSequence()
+ .filter { it.key.endsWith(target) }
+ .filter { it.value.dumpable is ProtoDumpable }
+ .minByOrNull { it.key.length }
+ ?.value?.dumpable as? ProtoDumpable
}
private data class RegisteredDumpable<T>(
diff --git a/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt b/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
index 8299b13d305f..0eab1afc4119 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
@@ -19,7 +19,7 @@ package com.android.systemui.dump
import android.content.Context
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.log.LogBuffer
import com.android.systemui.util.io.Files
import com.android.systemui.util.time.SystemClock
import java.io.IOException
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index f65e4809586f..d1d53cc9dd58 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -62,7 +62,8 @@ object Flags {
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply")
// TODO(b/279735475): Tracking Bug
- @JvmField val NEW_LIGHT_BAR_LOGIC = unreleasedFlag(279735475, "new_light_bar_logic")
+ @JvmField
+ val NEW_LIGHT_BAR_LOGIC = unreleasedFlag(279735475, "new_light_bar_logic", teamfood = true)
/**
* This flag is server-controlled and should stay as [unreleasedFlag] since we never want to
@@ -231,6 +232,11 @@ object Flags {
val REVAMPED_BOUNCER_MESSAGES =
unreleasedFlag(234, "revamped_bouncer_messages")
+ /** Whether to delay showing bouncer UI when face auth or active unlock are enrolled. */
+ // TODO(b/279794160): Tracking bug.
+ @JvmField
+ val DELAY_BOUNCER = unreleasedFlag(235, "delay_bouncer")
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -595,6 +601,8 @@ object Flags {
// 1700 - clipboard
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
+ // TODO(b/278714186) Tracking Bug
+ @JvmField val CLIPBOARD_IMAGE_TIMEOUT = unreleasedFlag(1702, "clipboard_image_timeout")
// 1800 - shade container
// TODO(b/265944639): Tracking Bug
@@ -618,7 +626,7 @@ object Flags {
// TODO(b/269132640): Tracking Bug
@JvmField
val APP_PANELS_REMOVE_APPS_ALLOWED =
- unreleasedFlag(2003, "app_panels_remove_apps_allowed", teamfood = true)
+ releasedFlag(2003, "app_panels_remove_apps_allowed")
// 2200 - biometrics (udfps, sfps, BiometricPrompt, etc.)
// TODO(b/259264861): Tracking Bug
@@ -694,6 +702,5 @@ object Flags {
// TODO(b/278761837): Tracking Bug
@JvmField
- val USE_NEW_ACTIVITY_STARTER = unreleasedFlag(2801, name = "use_new_activity_starter",
- teamfood = true)
+ val USE_NEW_ACTIVITY_STARTER = releasedFlag(2801, name = "use_new_activity_starter")
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index f64ed6078ddb..280710755ff6 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -97,6 +97,7 @@ import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
+import com.android.app.animation.Interpolators;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
@@ -116,7 +117,6 @@ import com.android.systemui.MultiListLayout.MultiListAdapter;
import com.android.systemui.animation.DialogCuj;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.animation.Expandable;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Background;
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
index 2ef5e19bf382..6bc763ce421e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyboard.backlight.ui.view
+import android.annotation.AttrRes
import android.annotation.ColorInt
import android.app.Dialog
import android.content.Context
@@ -31,6 +32,7 @@ import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.LinearLayout.LayoutParams
import android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
+import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.util.children
@@ -38,7 +40,7 @@ class KeyboardBacklightDialog(
context: Context,
initialCurrentLevel: Int,
initialMaxLevel: Int,
-) : Dialog(context) {
+) : Dialog(context, R.style.Theme_SystemUI_Dialog) {
private data class RootProperties(
val cornerRadius: Float,
@@ -69,9 +71,14 @@ class KeyboardBacklightDialog(
private lateinit var rootProperties: RootProperties
private lateinit var iconProperties: BacklightIconProperties
private lateinit var stepProperties: StepViewProperties
- @ColorInt var filledRectangleColor: Int = 0
- @ColorInt var emptyRectangleColor: Int = 0
- @ColorInt var backgroundColor: Int = 0
+ @ColorInt
+ var filledRectangleColor = getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
+ @ColorInt
+ var emptyRectangleColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorOutlineVariant)
+ @ColorInt
+ var backgroundColor = getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceBright)
+ @ColorInt var iconColor = getColorFromStyle(com.android.internal.R.attr.materialColorOnPrimary)
init {
currentLevel = initialCurrentLevel
@@ -90,9 +97,6 @@ class KeyboardBacklightDialog(
private fun updateResources() {
context.resources.apply {
- filledRectangleColor = getColor(R.color.backlight_indicator_step_filled, context.theme)
- emptyRectangleColor = getColor(R.color.backlight_indicator_step_empty, context.theme)
- backgroundColor = getColor(R.color.backlight_indicator_background, context.theme)
rootProperties =
RootProperties(
cornerRadius =
@@ -126,6 +130,11 @@ class KeyboardBacklightDialog(
}
}
+ @ColorInt
+ fun getColorFromStyle(@AttrRes colorId: Int): Int {
+ return Utils.getColorAttrDefaultColor(context, colorId)
+ }
+
fun updateState(current: Int, max: Int, forceRefresh: Boolean = false) {
if (maxLevel != max || forceRefresh) {
maxLevel = max
@@ -159,6 +168,7 @@ class KeyboardBacklightDialog(
private fun buildRootView(): LinearLayout {
val linearLayout =
LinearLayout(context).apply {
+ id = R.id.keyboard_backlight_dialog_container
orientation = LinearLayout.HORIZONTAL
layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
setPadding(
@@ -214,6 +224,7 @@ class KeyboardBacklightDialog(
private fun createBacklightIconView(): ImageView {
return ImageView(context).apply {
setImageResource(R.drawable.ic_keyboard_backlight)
+ setColorFilter(iconColor)
layoutParams =
FrameLayout.LayoutParams(iconProperties.width, iconProperties.height).apply {
gravity = Gravity.CENTER
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 2925d8dbd03a..9844ca02482b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -36,7 +36,7 @@ import androidx.core.math.MathUtils
import com.android.internal.R
import com.android.keyguard.KeyguardClockSwitchController
import com.android.keyguard.KeyguardViewController
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 1a126d72f9e9..2854de011ec6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -98,6 +98,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -121,7 +122,6 @@ import com.android.systemui.Dumpable;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index 5f2178df4346..5b71a2ed1991 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -32,6 +32,8 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -42,6 +44,7 @@ import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FailedAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.log.SessionTracker
@@ -63,6 +66,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
@@ -135,6 +139,7 @@ constructor(
@FaceDetectTableLog private val faceDetectLog: TableLogBuffer,
@FaceAuthTableLog private val faceAuthLog: TableLogBuffer,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val featureFlags: FeatureFlags,
dumpManager: DumpManager,
) : DeviceEntryFaceAuthRepository, Dumpable {
private var authCancellationSignal: CancellationSignal? = null
@@ -212,15 +217,21 @@ constructor(
.collect(Collectors.toSet())
dumpManager.registerCriticalDumpable("DeviceEntryFaceAuthRepositoryImpl", this)
- observeFaceAuthGatingChecks()
- observeFaceDetectGatingChecks()
- observeFaceAuthResettingConditions()
- listenForSchedulingWatchdog()
+ if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
+ observeFaceAuthGatingChecks()
+ observeFaceDetectGatingChecks()
+ observeFaceAuthResettingConditions()
+ listenForSchedulingWatchdog()
+ }
}
private fun listenForSchedulingWatchdog() {
keyguardTransitionInteractor.anyStateToGoneTransition
- .onEach { faceManager?.scheduleWatchdog() }
+ .filter { it.transitionState == TransitionState.FINISHED }
+ .onEach {
+ faceAuthLogger.watchdogScheduled()
+ faceManager?.scheduleWatchdog()
+ }
.launchIn(applicationScope)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
new file mode 100644
index 000000000000..252982fd019f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.content.Context
+import androidx.annotation.DimenRes
+import com.android.systemui.R
+import com.android.systemui.common.ui.data.repository.ConfigurationRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.doze.util.BurnInHelperWrapper
+import com.android.systemui.util.time.SystemClock
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+/** Encapsulates business-logic related to Ambient Display burn-in offsets. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class BurnInInteractor
+@Inject
+constructor(
+ private val context: Context,
+ private val burnInHelperWrapper: BurnInHelperWrapper,
+ @Application private val scope: CoroutineScope,
+ private val configurationRepository: ConfigurationRepository,
+ private val systemClock: SystemClock,
+) {
+ private val _dozeTimeTick = MutableStateFlow<Long>(0)
+ val dozeTimeTick: StateFlow<Long> = _dozeTimeTick.asStateFlow()
+
+ val udfpsBurnInXOffset: StateFlow<Int> =
+ burnInOffsetDefinedInPixels(R.dimen.udfps_burn_in_offset_x, isXAxis = true)
+ val udfpsBurnInYOffset: StateFlow<Int> =
+ burnInOffsetDefinedInPixels(R.dimen.udfps_burn_in_offset_y, isXAxis = false)
+ val udfpsBurnInProgress: StateFlow<Float> =
+ dozeTimeTick
+ .mapLatest { burnInHelperWrapper.burnInProgressOffset() }
+ .stateIn(scope, SharingStarted.Lazily, burnInHelperWrapper.burnInProgressOffset())
+
+ fun dozeTimeTick() {
+ _dozeTimeTick.value = systemClock.uptimeMillis()
+ }
+
+ /**
+ * Use for max burn-in offsets that are NOT specified in pixels. This flow will recalculate the
+ * max burn-in offset on any configuration changes. If the max burn-in offset is specified in
+ * pixels, use [burnInOffsetDefinedInPixels].
+ */
+ private fun burnInOffset(
+ @DimenRes maxBurnInOffsetResourceId: Int,
+ isXAxis: Boolean,
+ ): StateFlow<Int> {
+ return configurationRepository.onAnyConfigurationChange
+ .flatMapLatest {
+ val maxBurnInOffsetPixels =
+ context.resources.getDimensionPixelSize(maxBurnInOffsetResourceId)
+ dozeTimeTick.mapLatest { calculateOffset(maxBurnInOffsetPixels, isXAxis) }
+ }
+ .stateIn(
+ scope,
+ SharingStarted.Lazily,
+ calculateOffset(
+ context.resources.getDimensionPixelSize(maxBurnInOffsetResourceId),
+ isXAxis,
+ )
+ )
+ }
+
+ /**
+ * Use for max burn-in offBurn-in offsets that ARE specified in pixels. This flow will apply the
+ * a scale for any resolution changes. If the max burn-in offset is specified in dp, use
+ * [burnInOffset].
+ */
+ private fun burnInOffsetDefinedInPixels(
+ @DimenRes maxBurnInOffsetResourceId: Int,
+ isXAxis: Boolean,
+ ): StateFlow<Int> {
+ return configurationRepository.scaleForResolution
+ .flatMapLatest { scale ->
+ val maxBurnInOffsetPixels =
+ context.resources.getDimensionPixelSize(maxBurnInOffsetResourceId)
+ dozeTimeTick.mapLatest { calculateOffset(maxBurnInOffsetPixels, isXAxis, scale) }
+ }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ calculateOffset(
+ context.resources.getDimensionPixelSize(maxBurnInOffsetResourceId),
+ isXAxis,
+ configurationRepository.getResolutionScale(),
+ )
+ )
+ }
+
+ private fun calculateOffset(
+ maxBurnInOffsetPixels: Int,
+ isXAxis: Boolean,
+ scale: Float = 1f
+ ): Int {
+ return (burnInHelperWrapper.burnInOffset(maxBurnInOffsetPixels, isXAxis) * scale).toInt()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index e6568f20bc20..cde67f979132 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index c2d139c21074..7e9cbc1a9772 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
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 86f65dde4031..aca40195dbcf 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
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
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 3beac0b1322e..fc7bfb4e45f4 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
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index b5bcd45f03dd..39c630b1fa6f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 87f3164b33d2..0505d37262b0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index c0d5abc04e5d..47846d1f4118 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index a681c43be19f..bc55bd4b8c92 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -17,10 +17,10 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
+import com.android.app.animation.Interpolators
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index e650b9fc0e47..7c5641fcda9c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -19,7 +19,7 @@ package com.android.systemui.keyguard.domain.interactor
import com.android.keyguard.logging.KeyguardLogger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.plugins.log.LogLevel.VERBOSE
+import com.android.systemui.log.LogLevel.VERBOSE
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
index 38b9d508f81c..9d7477c13be6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui
import android.view.animation.Interpolator
-import com.android.systemui.animation.Interpolators.LINEAR
+import com.android.app.animation.Interpolators.LINEAR
import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index d96609c24dbd..c8d37a165a0e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -32,11 +32,11 @@ import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.Expandable
-import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.view.LaunchableLinearLayout
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.binder.IconViewBinder
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
index 6bbc6f61cc6f..c1aefc7bcbd7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
@@ -112,8 +112,6 @@ object KeyguardBouncerViewBinder {
viewModel.isShowing.collect { isShowing ->
view.visibility = if (isShowing) View.VISIBLE else View.INVISIBLE
if (isShowing) {
- // Reset Security Container entirely.
- view.visibility = View.VISIBLE
securityContainerController.reinflateViewFlipper {
// Reset Security Container entirely.
securityContainerController.onBouncerVisibilityChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index 8d6545a49a8a..2c9a9b3271e6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -16,8 +16,8 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
-import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
index f16827d4a54a..c1357863f3a5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
index bc9dc4f69102..c6187dde035b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
index a60665a81f0e..d3ea89ce1935 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
index ddce516a0fb2..6845c55b8385 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index df93d235245c..68810f909016 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
index efd3ad620de0..fefa1b29b576 100644
--- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
@@ -6,9 +6,8 @@ import com.android.keyguard.FaceAuthUiEvent
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.dagger.FaceAuthLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
import javax.inject.Inject
private const val TAG = "DeviceEntryFaceAuthRepositoryLog"
@@ -261,4 +260,8 @@ constructor(
{ "Attempting face auth again because of HW error: retry attempt $int1" }
)
}
+
+ fun watchdogScheduled() {
+ logBuffer.log(TAG, DEBUG, "FaceManager Biometric watchdog scheduled.")
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
index d6e29e0f2067..e4465acb14ab 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
@@ -19,9 +19,6 @@ package com.android.systemui.log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBufferHelper.Companion.adjustMaxSize
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogcatEchoTracker
-
import javax.inject.Inject
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
index edc278d1ae4f..f7277842c026 100644
--- a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
@@ -21,10 +21,11 @@ import android.graphics.Rect
import android.graphics.RectF
import androidx.core.graphics.toRectF
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.ERROR
import com.android.systemui.log.dagger.ScreenDecorationsLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.ERROR
+import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
private const val TAG = "ScreenDecorationsLog"
@@ -131,4 +132,36 @@ constructor(
fun onSensorLocationChanged() {
logBuffer.log(TAG, DEBUG, "AuthControllerCallback in ScreenDecorations triggered")
}
+
+ fun cameraProtectionShownOrHidden(
+ faceDetectionRunning: Boolean,
+ biometricPromptShown: Boolean,
+ requestedState: Boolean,
+ currentlyShowing: Boolean
+ ) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = faceDetectionRunning
+ bool2 = biometricPromptShown
+ bool3 = requestedState
+ bool4 = currentlyShowing
+ },
+ {
+ "isFaceDetectionRunning: $bool1, " +
+ "isBiometricPromptShowing: $bool2, " +
+ "requestedState: $bool3, " +
+ "currentState: $bool4"
+ }
+ )
+ }
+
+ fun biometricEvent(@CompileTimeConstant info: String) {
+ logBuffer.log(TAG, DEBUG, info)
+ }
+
+ fun cameraProtectionEvent(@CompileTimeConstant cameraProtectionEvent: String) {
+ logBuffer.log(TAG, DEBUG, cameraProtectionEvent)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricLog.java
index 4b774d3b2192..233f7a123ff4 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricLog.java
@@ -23,7 +23,7 @@ import java.lang.annotation.RetentionPolicy;
import javax.inject.Qualifier;
/**
- * A {@link com.android.systemui.plugins.log.LogBuffer} for BiometricMessages processing such as
+ * A {@link com.android.systemui.log.LogBuffer} for BiometricMessages processing such as
* {@link com.android.systemui.biometrics.FaceHelpMessageDeferral}
*/
@Qualifier
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java
index 5cca1ab2abe7..7d1f1c2709fa 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java
index 1d016d837b02..9ca0293fbd86 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java
index c9f78bcdeef8..7c5f4025117f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt
index 9f563fe4eae5..8732ef576335 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt
@@ -18,19 +18,19 @@ package com.android.systemui.log.dagger
import javax.inject.Qualifier
-/** A [com.android.systemui.plugins.log.LogBuffer] for keyguard clock logs. */
+/** A [com.android.systemui.log.LogBuffer] for keyguard clock logs. */
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class KeyguardClockLog
-/** A [com.android.systemui.plugins.log.LogBuffer] for small keyguard clock logs. */
+/** A [com.android.systemui.log.LogBuffer] for small keyguard clock logs. */
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class KeyguardSmallClockLog
-/** A [com.android.systemui.plugins.log.LogBuffer] for large keyguard clock logs. */
+/** A [com.android.systemui.log.LogBuffer] for large keyguard clock logs. */
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java
index 76d20bea4bdf..08d969b5eb77 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 658f6a087854..9be18ace79fa 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -22,13 +22,13 @@ import android.os.Looper;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogBufferFactory;
+import com.android.systemui.log.LogcatEchoTracker;
+import com.android.systemui.log.LogcatEchoTrackerDebug;
+import com.android.systemui.log.LogcatEchoTrackerProd;
import com.android.systemui.log.table.TableLogBuffer;
import com.android.systemui.log.table.TableLogBufferFactory;
-import com.android.systemui.plugins.log.LogBuffer;
-import com.android.systemui.plugins.log.LogcatEchoTracker;
-import com.android.systemui.plugins.log.LogcatEchoTrackerDebug;
-import com.android.systemui.plugins.log.LogcatEchoTrackerProd;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.util.Compile;
import com.android.systemui.util.wakelock.WakeLockLog;
@@ -209,7 +209,7 @@ public class LogModule {
@SysUISingleton
@CollapsedSbFragmentLog
public static LogBuffer provideCollapsedSbFragmentLogBuffer(LogBufferFactory factory) {
- return factory.create("CollapsedSbFragmentLog", 20);
+ return factory.create("CollapsedSbFragmentLog", 40);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java
index af433476b38c..1c00c93f4e38 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java
index f4dac6efe371..86a916ef6541 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java
index 73690ab6c24d..c67d8bebe313 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java
index 0c2cd92d1bb0..98e6556d7f53 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java
index 5b7f4bb103b4..dde0ee0796d4 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java
index 6d91f0c97c8a..b1c6dcfcb13b 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java
index 26af4964f7b8..20fc6ff445a6 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java
index 61daf9c8d71c..fcc184a317b8 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java
index a59afa0fed1b..760fbf3928b6 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java
index a2d381ec90f0..f1646a837132 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java
index 6f8ea7ff2e9b..a0b686487bec 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java
index 835d3490293c..8c8753a07339 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java
index 6e2bd7b2e1b5..7259eebf19b6 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java
index 77b1bf5fd630..e96e532f94bf 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java
index 295bf88d498f..973f6501bbfd 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java
index 9fd166b759d2..557a254e5c09 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java
index dd168bac5654..dd5010cf39a8 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java
index d24bfcb88188..bd0d298ebdee 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeWindowLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeWindowLog.java
index 1d2b68c3bf46..4aa2b1d84b21 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeWindowLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeWindowLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java
index af0f7c518e64..f26b3164f488 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java
index d58b538f2047..4d797c1a88cd 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java
index ba8b27c23ec1..8671dbfdf1fe 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
index 5c2321be4388..dbb6e8cbcc07 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
index 42fdd689df6c..592044e514be 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
@@ -27,19 +27,27 @@ import androidx.annotation.VisibleForTesting
*/
data class TableChange(
var timestamp: Long = 0,
- var columnPrefix: String = "",
- var columnName: String = "",
- var isInitial: Boolean = false,
- var type: DataType = DataType.EMPTY,
- var bool: Boolean = false,
- var int: Int? = null,
- var str: String? = null,
+ private var columnPrefix: String = "",
+ private var columnName: String = "",
+ private var isInitial: Boolean = false,
+ private var type: DataType = DataType.EMPTY,
+ private var bool: Boolean = false,
+ private var int: Int? = null,
+ private var str: String? = null,
) {
+ init {
+ // Truncate any strings that were passed into the constructor. [reset] and [set] will take
+ // care of the rest of the truncation.
+ this.columnPrefix = columnPrefix.take(MAX_STRING_LENGTH)
+ this.columnName = columnName.take(MAX_STRING_LENGTH)
+ this.str = str?.take(MAX_STRING_LENGTH)
+ }
+
/** Resets to default values so that the object can be recycled. */
fun reset(timestamp: Long, columnPrefix: String, columnName: String, isInitial: Boolean) {
this.timestamp = timestamp
- this.columnPrefix = columnPrefix
- this.columnName = columnName
+ this.columnPrefix = columnPrefix.take(MAX_STRING_LENGTH)
+ this.columnName = columnName.take(MAX_STRING_LENGTH)
this.isInitial = isInitial
this.type = DataType.EMPTY
this.bool = false
@@ -50,7 +58,7 @@ data class TableChange(
/** Sets this to store a string change. */
fun set(value: String?) {
type = DataType.STRING
- str = value
+ str = value?.take(MAX_STRING_LENGTH)
}
/** Sets this to store a boolean change. */
@@ -89,6 +97,8 @@ data class TableChange(
}
}
+ fun getColumnName() = columnName
+
fun getVal(): String {
val value =
when (type) {
@@ -109,5 +119,8 @@ data class TableChange(
companion object {
@VisibleForTesting const val IS_INITIAL_PREFIX = "**"
+ // Don't allow any strings larger than this length so that we have a hard upper limit on the
+ // size of the data stored by the buffer.
+ @VisibleForTesting const val MAX_STRING_LENGTH = 500
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
index 9d883cc10d6c..1d785ae62d87 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -20,8 +20,8 @@ import android.os.Trace
import com.android.systemui.Dumpable
import com.android.systemui.common.buffer.RingBuffer
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
import java.text.SimpleDateFormat
@@ -35,7 +35,7 @@ import kotlinx.coroutines.launch
* A logger that logs changes in table format.
*
* Some parts of System UI maintain a lot of pieces of state at once.
- * [com.android.systemui.plugins.log.LogBuffer] allows us to easily log change events:
+ * [com.android.systemui.log.LogBuffer] allows us to easily log change events:
* - 10-10 10:10:10.456: state2 updated to newVal2
* - 10-10 10:11:00.000: stateN updated to StateN(val1=true, val2=1)
* - 10-10 10:11:02.123: stateN updated to StateN(val1=true, val2=2)
@@ -291,7 +291,7 @@ class TableLogBuffer(
private fun echoToDesiredEndpoints(change: TableChange) {
if (
logcatEchoTracker.isBufferLoggable(bufferName = name, LogLevel.DEBUG) ||
- logcatEchoTracker.isTagLoggable(change.columnName, LogLevel.DEBUG)
+ logcatEchoTracker.isTagLoggable(change.getColumnName(), LogLevel.DEBUG)
) {
if (change.hasData()) {
localLogcat.d(name, change.logcatRepresentation())
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
index 42e742db2842..19e112487c46 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
@@ -21,7 +21,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBufferHelper.Companion.adjustMaxSize
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
index 37d956bd09eb..e38abc2228c4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
@@ -21,9 +21,9 @@ import android.animation.ObjectAnimator
import android.text.format.DateUtils
import androidx.annotation.UiThread
import androidx.lifecycle.Observer
+import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.media.controls.ui.SquigglyProgress
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
index f731dc064355..e2e269de71a0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
@@ -18,9 +18,9 @@ package com.android.systemui.media.controls.pipeline
import android.media.session.PlaybackState
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.MediaTimeoutListenerLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
private const val TAG = "MediaTimeout"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
index 095cf09a6c2c..9e53d77dec99 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
@@ -18,9 +18,9 @@ package com.android.systemui.media.controls.resume
import android.content.ComponentName
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.MediaBrowserLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** A logger for events in [ResumeMediaBrowser]. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
index 3669493f4e41..b46ebb22ff05 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
@@ -34,10 +34,10 @@ import android.util.AttributeSet
import android.util.MathUtils
import android.view.View
import androidx.annotation.Keep
+import com.android.app.animation.Interpolators
import com.android.internal.graphics.ColorUtils
import com.android.internal.graphics.ColorUtils.blendARGB
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import org.xmlpull.v1.XmlPullParser
private const val BACKGROUND_ANIM_DURATION = 370L
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
index dd5c2bf497cb..937a618df68f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
@@ -35,9 +35,9 @@ import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.MathUtils.lerp
import androidx.annotation.Keep
+import com.android.app.animation.Interpolators
import com.android.internal.graphics.ColorUtils
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import org.xmlpull.v1.XmlPullParser
private const val RIPPLE_ANIM_DURATION = 800L
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
index 9af11b924ec8..0ed24349bdf4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.media.controls.ui
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.MediaCarouselControllerLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** A debug logger for [MediaCarouselController]. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 40027a1d8f2c..f9d3094d6f00 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -72,6 +72,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.constraintlayout.widget.ConstraintSet;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.jank.InteractionJankMonitor;
@@ -82,7 +83,6 @@ import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.GhostedViewLaunchAnimatorController;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.bluetooth.BroadcastDialogController;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index 49e1665a0de9..fe8ebafdf9b4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -33,9 +33,9 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewGroupOverlay
import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
import com.android.keyguard.KeyguardViewController
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dreams.DreamOverlayStateController
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
index fdac33ac20b0..c781b7699b26 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.media.controls.ui
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.MediaViewLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
private const val TAG = "MediaView"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
index e9b2cf2b18d1..583c626d2156 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
@@ -31,8 +31,8 @@ import android.util.MathUtils.lerp
import android.util.MathUtils.lerpInv
import android.util.MathUtils.lerpInvSat
import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
import com.android.internal.graphics.ColorUtils
-import com.android.systemui.animation.Interpolators
import kotlin.math.abs
import kotlin.math.cos
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index 9ae4577b0394..46efac56ab9d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -17,6 +17,7 @@
package com.android.systemui.media.dagger;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogBufferFactory;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.MediaHierarchyManager;
@@ -30,16 +31,15 @@ import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
import com.android.systemui.media.taptotransfer.MediaTttFlags;
import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogBuffer;
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogBuffer;
-import com.android.systemui.plugins.log.LogBuffer;
-
-import java.util.Optional;
-
-import javax.inject.Named;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
+import java.util.Optional;
+
+import javax.inject.Named;
+
/** Dagger module for the media package. */
@Module(subcomponents = {
MediaComplicationComponent.class,
diff --git a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
index 5ace3ea8a05b..bbcf259418c8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
@@ -2,8 +2,8 @@ package com.android.systemui.media.muteawait
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.MediaMuteAwaitLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import javax.inject.Inject
/** Log messages for [MediaMuteAwaitConnectionManager]. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
index 78408fce5a36..66399d580582 100644
--- a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
@@ -2,8 +2,8 @@ package com.android.systemui.media.nearby
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.NearbyMediaDevicesLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import javax.inject.Inject
/** Log messages for [NearbyMediaDevicesManager]. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt
index 0e839c6dbc7a..eeda102702d2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt
@@ -16,8 +16,8 @@
package com.android.systemui.media.taptotransfer.common
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
/** A helper for logging media tap-to-transfer events. */
object MediaTttLoggerUtils {
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 78082c3eb3c6..77ff0362851a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -36,7 +36,7 @@ import android.view.View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE
import android.view.View.ACCESSIBILITY_LIVE_REGION_NONE
import com.android.internal.widget.CachingIconView
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.ui.binder.TintedIconViewBinder
import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogBuffer.java b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogBuffer.java
index 67e464c344c5..31ccb9afac9f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogBuffer.java
@@ -18,7 +18,7 @@ package com.android.systemui.media.taptotransfer.receiver;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt
index b0c6257df96c..1502df725a9c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt
@@ -18,8 +18,8 @@ package com.android.systemui.media.taptotransfer.receiver
import android.app.StatusBarManager
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
import com.android.systemui.media.taptotransfer.common.MediaTttLoggerUtils
-import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.temporarydisplay.TemporaryViewLogger
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogBuffer.java b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogBuffer.java
index a262e97864f3..edee4a808968 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogBuffer.java
@@ -18,7 +18,7 @@ package com.android.systemui.media.taptotransfer.sender;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
index 964a95b9be9a..03bcfc8113e3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
@@ -18,9 +18,9 @@ package com.android.systemui.media.taptotransfer.sender
import android.app.StatusBarManager
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.media.taptotransfer.common.MediaTttLoggerUtils
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** A logger for all events related to the media tap-to-transfer sender experience. */
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 94f01b87f936..146b5f57630e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -58,11 +58,11 @@ import android.widget.FrameLayout;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.ContextualButton;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
index 02180160fc11..10084bd4ccad 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
@@ -16,7 +16,7 @@
package com.android.systemui.navigationbar.buttons;
-import static com.android.systemui.animation.Interpolators.LINEAR;
+import static com.android.app.animation.Interpolators.LINEAR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -24,9 +24,6 @@ import android.animation.ValueAnimator;
import android.view.View;
import android.view.View.AccessibilityDelegate;
-import com.android.systemui.Dependency;
-import com.android.systemui.assist.AssistManager;
-
import java.util.ArrayList;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 590efbb66454..ff22398cc3be 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -48,10 +48,10 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
+import com.android.app.animation.Interpolators;
import com.android.internal.util.LatencyTracker;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.NavigationEdgeBackPlugin;
import com.android.systemui.settings.DisplayTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 166ba9fba166..79167f276576 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -15,7 +15,6 @@
package com.android.systemui.privacy
import android.content.Context
-import android.content.res.Configuration
import android.util.AttributeSet
import android.view.Gravity.CENTER_VERTICAL
import android.view.Gravity.END
@@ -103,11 +102,6 @@ class OngoingPrivacyChip @JvmOverloads constructor(
R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
}
- override fun onConfigurationChanged(newConfig: Configuration?) {
- super.onConfigurationChanged(newConfig)
- updateResources()
- }
-
private fun updateResources() {
iconMargin = context.resources
.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin)
@@ -116,11 +110,8 @@ class OngoingPrivacyChip @JvmOverloads constructor(
iconColor =
Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary)
- val height = context.resources
- .getDimensionPixelSize(R.dimen.ongoing_appops_chip_height)
val padding = context.resources
.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding)
- iconsContainer.layoutParams.height = height
iconsContainer.setPaddingRelative(padding, 0, padding, 0)
iconsContainer.background = context.getDrawable(R.drawable.statusbar_privacy_chip_bg)
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
index 03503fd1ff61..f9e1adff012b 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
@@ -18,9 +18,9 @@ package com.android.systemui.privacy.logging
import android.permission.PermissionGroupUsage
import com.android.systemui.log.dagger.PrivacyLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogMessage
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogMessage
import com.android.systemui.privacy.PrivacyDialog
import com.android.systemui.privacy.PrivacyItem
import java.text.SimpleDateFormat
diff --git a/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java b/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
index 80fbf9115065..b6a5ad6f2155 100644
--- a/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
@@ -16,11 +16,14 @@
package com.android.systemui.process.condition;
+import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.shared.condition.Condition;
import javax.inject.Inject;
+import kotlinx.coroutines.CoroutineScope;
+
/**
* {@link SystemProcessCondition} checks to make sure the current process is being ran by the
* System User.
@@ -29,8 +32,9 @@ public class SystemProcessCondition extends Condition {
private final ProcessWrapper mProcessWrapper;
@Inject
- public SystemProcessCondition(ProcessWrapper processWrapper) {
- super();
+ public SystemProcessCondition(@Application CoroutineScope scope,
+ ProcessWrapper processWrapper) {
+ super(scope);
mProcessWrapper = processWrapper;
}
@@ -42,4 +46,9 @@ public class SystemProcessCondition extends Condition {
@Override
protected void stop() {
}
+
+ @Override
+ protected int getStartStrategy() {
+ return START_EAGERLY;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index a7aac5a4824d..463c79c6696a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -26,7 +26,7 @@ import android.view.View.OnLayoutChangeListener;
import androidx.annotation.Nullable;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index fd3f70148a69..b8c2fad8c10d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -44,10 +44,10 @@ import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.compose.ComposeFacade;
import com.android.systemui.dump.DumpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
index 025fb228b829..cd52ec29177d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
@@ -1,8 +1,8 @@
package com.android.systemui.qs
import com.android.systemui.log.dagger.QSFragmentDisableLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
index 5b461a6d8bad..c00a81cbf12b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
@@ -21,14 +21,14 @@ import android.content.res.Configuration.ORIENTATION_PORTRAIT
import android.content.res.Configuration.Orientation
import android.service.quicksettings.Tile
import android.view.View
+import com.android.systemui.log.ConstantStringsLogger
+import com.android.systemui.log.ConstantStringsLoggerImpl
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.ERROR
+import com.android.systemui.log.LogLevel.VERBOSE
import com.android.systemui.log.dagger.QSConfigLog
import com.android.systemui.log.dagger.QSLog
-import com.android.systemui.plugins.log.ConstantStringsLogger
-import com.android.systemui.plugins.log.ConstantStringsLoggerImpl
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.ERROR
-import com.android.systemui.plugins.log.LogLevel.VERBOSE
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.statusbar.StatusBarState
import com.google.errorprone.annotations.CompileTimeConstant
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
index e85440cad6b0..a066242fd96b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
@@ -18,8 +18,8 @@ package com.android.systemui.qs.pipeline.dagger
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
import com.android.systemui.qs.pipeline.data.repository.TileSpecSettingsRepository
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
index 767ce919d027..b564334b5c52 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.qs.pipeline.shared.logging
import android.annotation.UserIdInt
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.qs.pipeline.dagger.QSTileListLog
import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 7f7f8ad6a4c1..2d9f7dd038bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -68,6 +68,7 @@ public class RotationLockTile extends QSTileImpl<BooleanState> implements
private final SensorPrivacyManager mPrivacyManager;
private final BatteryController mBatteryController;
private final SettingObserver mSetting;
+ private final boolean mAllowRotationResolver;
@Inject
public RotationLockTile(
@@ -105,6 +106,8 @@ public class RotationLockTile extends QSTileImpl<BooleanState> implements
}
};
mBatteryController.observe(getLifecycle(), this);
+ mAllowRotationResolver = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_allowRotationResolver);
}
@Override
@@ -145,7 +148,7 @@ public class RotationLockTile extends QSTileImpl<BooleanState> implements
final boolean powerSave = mBatteryController.isPowerSave();
final boolean cameraLocked = mPrivacyManager.isSensorPrivacyEnabled(CAMERA);
- final boolean cameraRotation =
+ final boolean cameraRotation = mAllowRotationResolver &&
!powerSave && !cameraLocked && hasSufficientPermission(mContext)
&& mController.isCameraRotationEnabled();
state.value = !rotationLocked;
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 69008cca6fe3..84f358c303ca 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -33,6 +33,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -60,11 +61,10 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
public static final int REQUEST_CODE = 2;
private static final int USER_ID_NOT_SPECIFIED = -1;
- private static final int NOTIFICATION_RECORDING_ID = 4274;
- private static final int NOTIFICATION_PROCESSING_ID = 4275;
- private static final int NOTIFICATION_VIEW_ID = 4273;
+ private static final int NOTIF_BASE_ID = 4273;
private static final String TAG = "RecordingService";
private static final String CHANNEL_ID = "screen_record";
+ private static final String GROUP_KEY = "screen_record_saved";
private static final String EXTRA_RESULT_CODE = "extra_resultCode";
private static final String EXTRA_PATH = "extra_path";
private static final String EXTRA_AUDIO_SOURCE = "extra_useAudio";
@@ -89,6 +89,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
private final UiEventLogger mUiEventLogger;
private final NotificationManager mNotificationManager;
private final UserContextProvider mUserContextTracker;
+ private int mNotificationId = NOTIF_BASE_ID;
@Inject
public RecordingService(RecordingController controller, @LongRunning Executor executor,
@@ -134,14 +135,23 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
}
String action = intent.getAction();
Log.d(TAG, "onStartCommand " + action);
+ NotificationChannel channel = new NotificationChannel(
+ CHANNEL_ID,
+ getString(R.string.screenrecord_title),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setDescription(getString(R.string.screenrecord_channel_description));
+ channel.enableVibration(true);
+ mNotificationManager.createNotificationChannel(channel);
int currentUserId = mUserContextTracker.getUserContext().getUserId();
UserHandle currentUser = new UserHandle(currentUserId);
switch (action) {
case ACTION_START:
+ // Get a unique ID for this recording's notifications
+ mNotificationId = NOTIF_BASE_ID + (int) SystemClock.uptimeMillis();
mAudioSource = ScreenRecordingAudioSource
.values()[intent.getIntExtra(EXTRA_AUDIO_SOURCE, 0)];
- Log.d(TAG, "recording with audio source" + mAudioSource);
+ Log.d(TAG, "recording with audio source " + mAudioSource);
mShowTaps = intent.getBooleanExtra(EXTRA_SHOW_TAPS, false);
MediaProjectionCaptureTarget captureTarget =
intent.getParcelableExtra(EXTRA_CAPTURE_TARGET,
@@ -169,7 +179,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
} else {
updateState(false);
createErrorNotification();
- stopForeground(true);
+ stopForeground(STOP_FOREGROUND_DETACH);
stopSelf();
return Service.START_NOT_STICKY;
}
@@ -200,7 +210,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
startActivity(Intent.createChooser(shareIntent, shareLabel)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
// Remove notification
- mNotificationManager.cancelAsUser(null, NOTIFICATION_VIEW_ID, currentUser);
+ mNotificationManager.cancelAsUser(null, mNotificationId, currentUser);
return false;
}, false, false);
@@ -260,14 +270,6 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
@VisibleForTesting
protected void createErrorNotification() {
Resources res = getResources();
- NotificationChannel channel = new NotificationChannel(
- CHANNEL_ID,
- getString(R.string.screenrecord_title),
- NotificationManager.IMPORTANCE_DEFAULT);
- channel.setDescription(getString(R.string.screenrecord_channel_description));
- channel.enableVibration(true);
- mNotificationManager.createNotificationChannel(channel);
-
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
res.getString(R.string.screenrecord_title));
@@ -277,7 +279,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
.setSmallIcon(R.drawable.ic_screenrecord)
.setContentTitle(notificationTitle)
.addExtras(extras);
- startForeground(NOTIFICATION_RECORDING_ID, builder.build());
+ startForeground(mNotificationId, builder.build());
}
@VisibleForTesting
@@ -288,14 +290,6 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
@VisibleForTesting
protected void createRecordingNotification() {
Resources res = getResources();
- NotificationChannel channel = new NotificationChannel(
- CHANNEL_ID,
- getString(R.string.screenrecord_title),
- NotificationManager.IMPORTANCE_DEFAULT);
- channel.setDescription(getString(R.string.screenrecord_channel_description));
- channel.enableVibration(true);
- mNotificationManager.createNotificationChannel(channel);
-
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
res.getString(R.string.screenrecord_title));
@@ -323,7 +317,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
.addAction(stopAction)
.addExtras(extras);
- startForeground(NOTIFICATION_RECORDING_ID, builder.build());
+ startForeground(mNotificationId, builder.build());
}
@VisibleForTesting
@@ -337,11 +331,12 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
res.getString(R.string.screenrecord_title));
- Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID)
+ Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle(notificationTitle)
.setContentText(
getResources().getString(R.string.screenrecord_background_processing_label))
.setSmallIcon(R.drawable.ic_screenrecord)
+ .setGroup(GROUP_KEY)
.addExtras(extras);
return builder.build();
}
@@ -378,6 +373,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
PendingIntent.FLAG_IMMUTABLE))
.addAction(shareAction)
.setAutoCancel(true)
+ .setGroup(GROUP_KEY)
.addExtras(extras);
// Add thumbnail if available
@@ -391,6 +387,24 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
return builder.build();
}
+ /**
+ * Adds a group notification so that save notifications from multiple recordings are
+ * grouped together, and the foreground service recording notification is not
+ */
+ private void postGroupNotification(UserHandle currentUser) {
+ Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ getResources().getString(R.string.screenrecord_title));
+ Notification groupNotif = new Notification.Builder(this, CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_screenrecord)
+ .setContentTitle(getResources().getString(R.string.screenrecord_save_title))
+ .setGroup(GROUP_KEY)
+ .setGroupSummary(true)
+ .setExtras(extras)
+ .build();
+ mNotificationManager.notifyAsUser(TAG, NOTIF_BASE_ID, groupNotif, currentUser);
+ }
+
private void stopService() {
stopService(USER_ID_NOT_SPECIFIED);
}
@@ -423,27 +437,26 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
Log.e(TAG, "stopRecording called, but recorder was null");
}
updateState(false);
+ stopForeground(STOP_FOREGROUND_DETACH);
stopSelf();
}
private void saveRecording(int userId) {
UserHandle currentUser = new UserHandle(userId);
- mNotificationManager.notifyAsUser(null, NOTIFICATION_PROCESSING_ID,
+ mNotificationManager.notifyAsUser(null, mNotificationId,
createProcessingNotification(), currentUser);
mLongExecutor.execute(() -> {
try {
Log.d(TAG, "saving recording");
Notification notification = createSaveNotification(getRecorder().save());
- if (!mController.isRecording()) {
- mNotificationManager.notifyAsUser(null, NOTIFICATION_VIEW_ID, notification,
- currentUser);
- }
+ postGroupNotification(currentUser);
+ mNotificationManager.notifyAsUser(null, mNotificationId, notification,
+ currentUser);
} catch (IOException e) {
Log.e(TAG, "Error saving screen recording: " + e.getMessage());
showErrorToast(R.string.screenrecord_delete_error);
- } finally {
- mNotificationManager.cancelAsUser(null, NOTIFICATION_PROCESSING_ID, currentUser);
+ mNotificationManager.cancelAsUser(null, mNotificationId, currentUser);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 137a99ef39b8..926ede99f5a9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -22,10 +22,10 @@ import static android.view.MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
-import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
-import static com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.GENERIC;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -88,6 +88,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
@@ -111,7 +112,6 @@ import com.android.systemui.Dumpable;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.Classifier;
@@ -1513,6 +1513,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
mKeyguardStatusViewController.isClockTopAligned());
mClockPositionAlgorithm.run(mClockPositionResult);
+ mKeyguardStatusViewController.setLockscreenClockY(
+ mClockPositionAlgorithm.getExpandedPreferredClockY());
mKeyguardBottomAreaInteractor.setClockPosition(
mClockPositionResult.clockX, mClockPositionResult.clockY);
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index fb7c5c2e31fa..31b361f83758 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -18,7 +18,6 @@ package com.android.systemui.shade
import android.view.View
import android.view.ViewGroup
-import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.WindowInsets
import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.widget.ConstraintSet
@@ -62,6 +61,7 @@ class NotificationsQSContainerController @Inject constructor(
private var isQSCustomizing = false
private var isQSCustomizerAnimating = false
+ private var shadeHeaderHeight = 0
private var largeScreenShadeHeaderHeight = 0
private var largeScreenShadeHeaderActive = false
private var notificationsBottomMargin = 0
@@ -146,6 +146,8 @@ class NotificationsQSContainerController @Inject constructor(
R.dimen.notification_panel_margin_bottom)
largeScreenShadeHeaderHeight =
resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
+ shadeHeaderHeight =
+ resources.getDimensionPixelSize(R.dimen.qs_header_height)
panelMarginHorizontal = resources.getDimensionPixelSize(
R.dimen.notification_panel_margin_horizontal)
topMargin = if (largeScreenShadeHeaderActive) {
@@ -245,7 +247,7 @@ class NotificationsQSContainerController @Inject constructor(
if (largeScreenShadeHeaderActive) {
constraintSet.constrainHeight(R.id.split_shade_status_bar, largeScreenShadeHeaderHeight)
} else {
- constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT)
+ constraintSet.constrainHeight(R.id.split_shade_status_bar, shadeHeaderHeight)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index a1fa8fbf9075..abdd1a94d93c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -50,6 +50,7 @@ import android.view.WindowMetrics;
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
@@ -59,7 +60,6 @@ import com.android.internal.policy.SystemBarUtils;
import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index 86ae4ecf6e70..f080d3dfab1d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -34,10 +34,10 @@ import android.view.WindowInsets
import android.widget.TextView
import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.motion.widget.MotionLayout
+import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
import com.android.systemui.Dumpable
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index 1839e13dcdec..25073c1b64db 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -18,8 +18,8 @@ package com.android.systemui.shade
import android.view.MotionEvent
import com.android.systemui.log.dagger.ShadeLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.shade.ShadeViewController.Companion.FLING_COLLAPSE
import com.android.systemui.shade.ShadeViewController.Companion.FLING_EXPAND
import com.android.systemui.shade.ShadeViewController.Companion.FLING_HIDE
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
index 9851625b6152..d8d42795be58 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
@@ -18,12 +18,12 @@ package com.android.systemui.shade
import android.view.WindowManager
import com.android.systemui.log.dagger.ShadeWindowLog
-import com.android.systemui.plugins.log.ConstantStringsLogger
-import com.android.systemui.plugins.log.ConstantStringsLoggerImpl
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogMessage
+import com.android.systemui.log.ConstantStringsLogger
+import com.android.systemui.log.ConstantStringsLoggerImpl
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogMessage
import javax.inject.Inject
private const val TAG = "systemui.shadewindow"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
index 90c52bd8c9f4..e008ec0dc75c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
@@ -18,8 +18,8 @@ package com.android.systemui.statusbar
import android.app.PendingIntent
import com.android.systemui.log.dagger.NotifInteractionLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 63179dac7b8c..c1ebf1236def 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -18,8 +18,8 @@ package com.android.systemui.statusbar;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 54b341f529b0..1a32d70a9745 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -38,8 +38,8 @@ import android.view.ViewAnimationUtils;
import android.view.animation.Interpolator;
import android.widget.ImageView;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.wm.shell.animation.FlingAnimationUtils;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index ea5a1c0fbe70..0ea257010751 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -41,8 +41,8 @@ import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewCont
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_USER_LOCKED;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
+import static com.android.systemui.log.LogLevel.ERROR;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
-import static com.android.systemui.plugins.log.LogLevel.ERROR;
import android.app.AlarmManager;
import android.app.admin.DevicePolicyManager;
@@ -95,8 +95,8 @@ import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.log.LogLevel;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 9421524c73a7..823bb355a307 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -16,7 +16,7 @@ import android.util.AttributeSet
import android.util.MathUtils.lerp
import android.view.View
import android.view.animation.PathInterpolator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold
import com.android.systemui.util.getColorWithAlpha
import com.android.systemui.util.leak.RotationUtils
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 7f016f304e05..b61f2438324b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -18,7 +18,7 @@ import com.android.systemui.Dumpable
import com.android.systemui.ExpandHelper
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.biometrics.UdfpsKeyguardViewController
import com.android.systemui.classifier.Classifier
import com.android.systemui.classifier.FalsingCollector
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 72ae16e607c8..fb88a96c38c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -44,9 +44,9 @@ import android.util.Log;
import android.view.View;
import android.widget.ImageView;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index a3bd247668fe..0e20df6ecfba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -33,7 +33,7 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat
import androidx.dynamicanimation.animation.SpringAnimation
import androidx.dynamicanimation.animation.SpringForce
import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 49c7950fd923..9d7f3be4dfe7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -35,10 +35,10 @@ import android.view.animation.PathInterpolator;
import androidx.annotation.NonNull;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 821a17279cb3..fc6eaa804f86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -31,7 +31,7 @@ import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
index 575f354c6620..f1e51e21a9e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
@@ -4,7 +4,7 @@ import android.content.Context
import android.content.res.Configuration
import android.util.MathUtils
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.policy.ConfigurationController
import dagger.assisted.Assisted
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
index 572c0e0da262..3d574caf3192 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
@@ -8,7 +8,7 @@ import android.util.MathUtils
import android.view.animation.PathInterpolator
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.qs.QS
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 129c8594e48e..91c08a062b54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -26,7 +26,6 @@ import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.Notification;
import android.content.Context;
-import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -53,10 +52,10 @@ import android.view.animation.Interpolator;
import androidx.core.graphics.ColorUtils;
+import com.android.app.animation.Interpolators;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.util.drawable.DrawableSize;
@@ -76,9 +75,9 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
*/
private static final float DARK_ALPHA_BOOST = 0.67f;
/**
- * Status icons are currently drawn with the intention of being 17sp tall, but we
- * want to scale them (in a way that doesn't require an asset dump) down 2sp. So
- * 17sp * (15 / 17) = 15sp, the new height. After the first call to {@link #reloadDimens} all
+ * Status icons are currently drawn with the intention of being 17dp tall, but we
+ * want to scale them (in a way that doesn't require an asset dump) down 2dp. So
+ * 17dp * (15 / 17) = 15dp, the new height. After the first call to {@link #reloadDimens} all
* values will be in px.
*/
private float mSystemIconDesiredHeight = 15f;
@@ -145,7 +144,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
private String mNumberText;
private StatusBarNotification mNotification;
private final boolean mBlocked;
- private Configuration mConfiguration;
+ private int mDensity;
private boolean mNightMode;
private float mIconScale = 1.0f;
private final Paint mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -199,8 +198,9 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
mNumberPain.setAntiAlias(true);
setNotification(sbn);
setScaleType(ScaleType.CENTER);
- mConfiguration = new Configuration(context.getResources().getConfiguration());
- mNightMode = (mConfiguration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+ mDensity = context.getResources().getDisplayMetrics().densityDpi;
+ Configuration configuration = context.getResources().getConfiguration();
+ mNightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
initializeDecorColor();
reloadDimens();
@@ -214,7 +214,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
mAlwaysScaleIcon = true;
reloadDimens();
maybeUpdateIconScaleDimens();
- mConfiguration = new Configuration(context.getResources().getConfiguration());
+ mDensity = context.getResources().getDisplayMetrics().densityDpi;
}
/** Should always be preceded by {@link #reloadDimens()} */
@@ -231,17 +231,12 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
private void updateIconScaleForNotifications() {
final float imageBounds = mIncreasedSize ?
mStatusBarIconDrawingSizeIncreased : mStatusBarIconDrawingSize;
- float iconHeight = getIconHeight();
- if (iconHeight != 0) {
- mIconScale = imageBounds / iconHeight;
- } else {
- final int outerBounds = mStatusBarIconSize;
- mIconScale = imageBounds / (float) outerBounds;
- }
+ final int outerBounds = mStatusBarIconSize;
+ mIconScale = imageBounds / (float)outerBounds;
updatePivot();
}
- // Makes sure that all icons are scaled to the same height (15sp). If we cannot get a height
+ // Makes sure that all icons are scaled to the same height (15dp). If we cannot get a height
// for the icon, it uses the default SCALE (15f / 17f) which is the old behavior
private void updateIconScaleForSystemIcons() {
float iconHeight = getIconHeight();
@@ -272,10 +267,12 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- final int configDiff = newConfig.diff(mConfiguration);
- mConfiguration.setTo(newConfig);
- if ((configDiff & (ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_FONT_SCALE)) != 0) {
- updateIconDimens();
+ int density = newConfig.densityDpi;
+ if (density != mDensity) {
+ mDensity = density;
+ reloadDimens();
+ updateDrawable();
+ maybeUpdateIconScaleDimens();
}
boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
@@ -285,15 +282,6 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
}
}
- /**
- * Update the icon dimens and drawable with current resources
- */
- public void updateIconDimens() {
- reloadDimens();
- updateDrawable();
- maybeUpdateIconScaleDimens();
- }
-
private void reloadDimens() {
boolean applyRadius = mDotRadius == mStaticDotRadius;
Resources res = getResources();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 79d01b4a73fd..d6a14604ffb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -42,6 +42,7 @@ import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
@@ -49,7 +50,6 @@ import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 2fa27ee454e8..67ab0601cbf8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -25,8 +25,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.TransformState;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index 6e74542691a5..2465c21c956f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -73,9 +73,9 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.log.LogBuffer;
+import com.android.systemui.log.LogLevel;
import com.android.systemui.log.dagger.StatusBarNetworkControllerLog;
-import com.android.systemui.plugins.log.LogBuffer;
-import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
@@ -87,6 +87,8 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.CarrierConfigTracker;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -101,8 +103,6 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
-import kotlin.Unit;
-
/** Platform implementation of the network controller. **/
@SysUISingleton
public class NetworkControllerImpl extends BroadcastReceiver
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index bfc4e9c47db5..eddb6835318d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -26,7 +26,7 @@ import android.view.View
import android.widget.FrameLayout
import com.android.internal.annotations.GuardedBy
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
index 9ce6b02e55d9..a67c26c06cb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
@@ -18,8 +18,8 @@ package com.android.systemui.statusbar.gesture
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.SwipeUpLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import javax.inject.Inject
/** Log messages for [SwipeUpGestureHandler]. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index 0446165be5fc..b09b9f42e6af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -21,8 +21,8 @@ import android.util.Pools;
import android.view.View;
import android.widget.ImageView;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.notification.row.HybridNotificationView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
index c22dbf615190..785e65dd4026 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
@@ -3,7 +3,7 @@ package com.android.systemui.statusbar.notification
import android.util.MathUtils
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.animation.LaunchAnimator
import kotlin.math.min
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
index c22cd1ba4bc8..5a14200677b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -23,13 +23,13 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import com.android.app.animation.Interpolators;
import com.android.internal.widget.IMessagingLayout;
import com.android.internal.widget.MessagingGroup;
import com.android.internal.widget.MessagingImageMessage;
import com.android.internal.widget.MessagingLinearLayout;
import com.android.internal.widget.MessagingMessage;
import com.android.internal.widget.MessagingPropertyAnimator;
-import com.android.systemui.animation.Interpolators;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
index 3058fbbc1031..a3a72d92c2e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification
import com.android.systemui.log.dagger.NotifInteractionLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
index 3fc7b132f38f..a0456985e8d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
@@ -24,8 +24,8 @@ import android.graphics.ColorMatrixColorFilter;
import android.view.View;
import android.widget.ImageView;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import java.util.function.Consumer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index fe0b28d16239..9ba219903272 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -21,8 +21,8 @@ import android.view.animation.Interpolator
import androidx.annotation.VisibleForTesting
import androidx.core.animation.ObjectAnimator
import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators
-import com.android.systemui.animation.InterpolatorsAndroidX
+import com.android.app.animation.Interpolators
+import com.android.app.animation.InterpolatorsAndroidX
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
index dd3c2a9df3e5..f7679ed058c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -13,9 +13,9 @@
package com.android.systemui.statusbar.notification
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.dagger.NotificationLockscreenLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
import com.android.systemui.statusbar.StatusBarState
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
index 5d07cac78682..57d20246ea14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
@@ -24,7 +24,7 @@ import android.util.Property;
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ViewState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
index 9582dfad35cd..487a5f87d0bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.statusbar.notification
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.dagger.NotificationRemoteInputLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
import javax.inject.Inject
/** Logger class for [RemoteInputController]. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 9f9fba437869..90eb630949fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -23,11 +23,11 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.app.animation.Interpolators;
import com.android.internal.widget.MessagingImageMessage;
import com.android.internal.widget.MessagingPropertyAnimator;
import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
index dc1627438490..16f1a45ba83f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
@@ -22,7 +22,7 @@ import android.animation.ValueAnimator
import android.view.View
import android.view.ViewGroup
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
/**
* Class to help with fading of view groups without fading one subview
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
index 68d1319699d4..39d0833c57d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.coalescer
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import javax.inject.Inject
class GroupCoalescerLogger @Inject constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
index 2919def16304..79c63e6b0db1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
@@ -1,8 +1,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.notification.row.NotificationGuts
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
index 32c3c6665b6f..e17ce5cff37d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
@@ -3,8 +3,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.util.Log
import com.android.systemui.log.dagger.NotificationHeadsUpLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import javax.inject.Inject
private const val TAG = "HeadsUpCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
index 6503a6403eaa..1f8ec3411bcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.notification.collection.coordinator
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.UnseenNotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
private const val TAG = "KeyguardCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
index 9558f47af795..6271d38f1efa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
index d80445491bda..1f4861a10e75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import javax.inject.Inject
private const val TAG = "ShadeEventCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index 4adc90aec0fb..f13ff6814df8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -17,10 +17,10 @@
package com.android.systemui.statusbar.notification.collection.listbuilder
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.INFO
-import com.android.systemui.plugins.log.LogLevel.WARNING
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.LogLevel.WARNING
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 911a2d0c2b36..20de785bc9bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -21,12 +21,12 @@ import android.service.notification.NotificationListenerService
import android.service.notification.NotificationListenerService.RankingMap
import android.service.notification.StatusBarNotification
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.ERROR
-import com.android.systemui.plugins.log.LogLevel.INFO
-import com.android.systemui.plugins.log.LogLevel.WARNING
-import com.android.systemui.plugins.log.LogLevel.WTF
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.ERROR
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.log.LogLevel.WTF
import com.android.systemui.statusbar.notification.collection.NotifCollection
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason
import com.android.systemui.statusbar.notification.collection.NotifCollection.FutureDismissal
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
index 9c71e5c1054c..07fd349d3786 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.render
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
import com.android.systemui.util.Compile
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
index 1e22c2cd7c0e..a880b7157708 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.render
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import java.lang.RuntimeException
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
index d4f11fc141f0..0b31265963ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
@@ -1,8 +1,8 @@
package com.android.systemui.statusbar.notification.interruption
import com.android.systemui.log.dagger.NotificationHeadsUpLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
index 115e050258c3..5bac2a9350a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
@@ -19,10 +19,10 @@ package com.android.systemui.statusbar.notification.interruption
import android.util.Log
import com.android.systemui.log.dagger.NotificationInterruptLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.INFO
-import com.android.systemui.plugins.log.LogLevel.WARNING
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.LogLevel.WARNING
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import com.android.systemui.util.Compile
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt
index 10197a38527e..fe03b2ad6a32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.notification.logging
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.dagger.NotificationRenderLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.NotificationSection
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 66d4c3a97773..8af488ea443d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -31,12 +31,12 @@ import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -733,12 +733,16 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
super.dump(pw, args);
if (DUMP_VERBOSE) {
DumpUtilsKt.withIncreasedIndent(pw, () -> {
- pw.println("mBackgroundNormal: " + mBackgroundNormal);
- if (mBackgroundNormal != null) {
- DumpUtilsKt.withIncreasedIndent(pw, () -> {
- mBackgroundNormal.dump(pw, args);
- });
- }
+ dumpBackgroundView(pw, args);
+ });
+ }
+ }
+
+ protected void dumpBackgroundView(IndentingPrintWriter pw, String[] args) {
+ pw.println("Background View: " + mBackgroundNormal);
+ if (DUMP_VERBOSE && mBackgroundNormal != null) {
+ DumpUtilsKt.withIncreasedIndent(pw, () -> {
+ mBackgroundNormal.dump(pw, args);
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 597813344d6e..ba8a5f3de45c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -64,6 +64,7 @@ import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -72,7 +73,6 @@ import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -3593,6 +3593,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
// Skip super call; dump viewState ourselves
pw.println("Notification: " + mEntry.getKey());
DumpUtilsKt.withIncreasedIndent(pw, () -> {
+ pw.println(this);
pw.print("visibility: " + getVisibility());
pw.print(", alpha: " + getAlpha());
pw.print(", translation: " + getTranslation());
@@ -3612,6 +3613,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
pw.println("no viewState!!!");
}
pw.println(getRoundableState().debugString());
+ dumpBackgroundView(pw, args);
int transientViewCount = mChildrenContainer == null
? 0 : mChildrenContainer.getTransientViewCount();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
index b56bae12be6c..7a2bee91e972 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -45,10 +45,10 @@ import android.widget.Toast;
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 5edff5f4e5d2..f0e15c27b7a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -32,14 +32,15 @@ import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.Roundable;
import com.android.systemui.statusbar.notification.RoundableState;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.util.Compile;
import com.android.systemui.util.DumpUtilsKt;
import java.io.PrintWriter;
@@ -52,7 +53,8 @@ import java.util.List;
public abstract class ExpandableView extends FrameLayout implements Dumpable, Roundable {
private static final String TAG = "ExpandableView";
/** whether the dump() for this class should include verbose details */
- protected static final boolean DUMP_VERBOSE = false;
+ protected static final boolean DUMP_VERBOSE =
+ Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
private RoundableState mRoundableState = null;
protected OnHeightChangedListener mOnHeightChangedListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
index 46fef3f973a7..45be0b151870 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.row
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index da8d2d524456..647505cea71b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.systemui.util.ColorUtilKt.hexColorString;
+
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
@@ -27,6 +29,9 @@ import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.util.ArrayUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
@@ -44,6 +49,7 @@ public class NotificationBackgroundView extends View implements Dumpable {
private int mClipTopAmount;
private int mClipBottomAmount;
private int mTintColor;
+ @Nullable private Integer mRippleColor;
private final float[] mCornerRadii = new float[8];
private boolean mBottomIsRounded;
private boolean mBottomAmountClips = true;
@@ -127,6 +133,7 @@ public class NotificationBackgroundView extends View implements Dumpable {
unscheduleDrawable(mBackground);
}
mBackground = background;
+ mRippleColor = null;
mBackground.mutate();
if (mBackground != null) {
mBackground.setCallback(this);
@@ -215,6 +222,9 @@ public class NotificationBackgroundView extends View implements Dumpable {
if (mBackground instanceof RippleDrawable) {
RippleDrawable ripple = (RippleDrawable) mBackground;
ripple.setColor(ColorStateList.valueOf(color));
+ mRippleColor = color;
+ } else {
+ mRippleColor = null;
}
}
@@ -290,7 +300,7 @@ public class NotificationBackgroundView extends View implements Dumpable {
}
@Override
- public void dump(PrintWriter pw, String[] args) {
+ public void dump(PrintWriter pw, @NonNull String[] args) {
pw.println("mDontModifyCorners: " + mDontModifyCorners);
pw.println("mClipTopAmount: " + mClipTopAmount);
pw.println("mClipBottomAmount: " + mClipBottomAmount);
@@ -299,5 +309,8 @@ public class NotificationBackgroundView extends View implements Dumpable {
pw.println("mBottomAmountClips: " + mBottomAmountClips);
pw.println("mActualWidth: " + mActualWidth);
pw.println("mActualHeight: " + mActualHeight);
+ pw.println("mTintColor: " + hexColorString(mTintColor));
+ pw.println("mRippleColor: " + hexColorString(mRippleColor));
+ pw.println("mBackground: " + mBackground);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 4522e41daf91..b4bfded58e4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -966,7 +966,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
@Override
public ApplicationInfo getApplicationInfo() {
- ApplicationInfo applicationInfo = super.getApplicationInfo();
+ ApplicationInfo applicationInfo = new ApplicationInfo(super.getApplicationInfo());
applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
return applicationInfo;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index f21db0bde59a..9bc03336c3b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -25,7 +25,7 @@ import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
-import static com.android.systemui.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
import static java.lang.annotation.RetentionPolicy.SOURCE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index 596bdc09efe4..047db2046529 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -33,9 +33,9 @@ import android.widget.FrameLayout;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 8a50f2f527fa..99a77550cc76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -20,7 +20,7 @@ import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
-import static com.android.systemui.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
import static java.lang.annotation.RetentionPolicy.SOURCE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index bafc474d7123..5a129fccff06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -39,9 +39,9 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
index ce11be36acf3..c3dd92a51a91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.statusbar.notification.row
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index 5f4c9267ee4a..d5d7f75fbaa1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -45,11 +45,11 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
index 8a5d29a1ae2d..684a276ed635 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.row
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index 5aaf63f8d32d..b24cec150941 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -23,8 +23,8 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.animation.Interpolators;
import java.util.function.Consumer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 2c59c2e8a06f..ef5e86f06ef0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -34,10 +34,10 @@ import android.widget.TextView;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.notification.CustomInterpolatorTransformation;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
index 7f3381ccd38a..d73bbebe40b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
@@ -22,8 +22,8 @@ import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index 0b435fe9dcc6..9a33a9440602 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -26,7 +26,7 @@ import android.graphics.Rect;
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
import com.android.systemui.statusbar.notification.row.ExpandableView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
index b61c55edadcd..f9531876e30d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
@@ -18,8 +18,8 @@ package com.android.systemui.statusbar.notification.stack
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.NotificationSectionLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import javax.inject.Inject
private const val TAG = "NotifSections"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index edff8770479a..cf051fbc2504 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -75,6 +75,7 @@ import android.view.animation.Interpolator;
import android.widget.OverScroller;
import android.widget.ScrollView;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.jank.InteractionJankMonitor;
@@ -86,7 +87,6 @@ import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
index 64dd6dcd3008..5b0ec1d14edc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
@@ -1,9 +1,9 @@
package com.android.systemui.statusbar.notification.stack
import com.android.systemui.log.dagger.NotificationHeadsUpLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index ee72943bef57..f07dd00827b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -22,9 +22,9 @@ import android.animation.ValueAnimator;
import android.util.Property;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardSliceView;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
index f5de678a8536..cca84b3330a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
@@ -1,8 +1,8 @@
package com.android.systemui.statusbar.notification.stack
import com.android.systemui.log.dagger.NotificationHeadsUpLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index d07da381a186..f4605be2b9c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -26,9 +26,9 @@ import android.util.Property;
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.app.animation.Interpolators;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.NotificationFadeAware.FadeOptimizedNotification;
import com.android.systemui.statusbar.notification.PropertyAnimator;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 9dce332985f9..459071280a1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -33,9 +33,9 @@ import android.os.SystemClock;
import android.util.Log;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 89c3946939a2..618120d406cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -37,6 +37,7 @@ import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.domain.interactor.BurnInInteractor;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -56,10 +57,12 @@ import java.util.ArrayList;
import javax.inject.Inject;
+import kotlinx.coroutines.ExperimentalCoroutinesApi;
+
/**
* Implementation of DozeHost for SystemUI.
*/
-@SysUISingleton
+@ExperimentalCoroutinesApi @SysUISingleton
public final class DozeServiceHost implements DozeHost {
private static final String TAG = "DozeServiceHost";
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
@@ -89,6 +92,7 @@ public final class DozeServiceHost implements DozeHost {
private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
private final AuthController mAuthController;
private final NotificationIconAreaController mNotificationIconAreaController;
+ private final BurnInInteractor mBurnInInteractor;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private ShadeViewController mNotificationPanel;
private View mAmbientIndicationContainer;
@@ -110,7 +114,8 @@ public final class DozeServiceHost implements DozeHost {
NotificationShadeWindowController notificationShadeWindowController,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
AuthController authController,
- NotificationIconAreaController notificationIconAreaController) {
+ NotificationIconAreaController notificationIconAreaController,
+ BurnInInteractor burnInInteractor) {
super();
mDozeLog = dozeLog;
mPowerManager = powerManager;
@@ -129,6 +134,7 @@ public final class DozeServiceHost implements DozeHost {
mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
mAuthController = authController;
mNotificationIconAreaController = notificationIconAreaController;
+ mBurnInInteractor = burnInInteractor;
mHeadsUpManagerPhone.addListener(mOnHeadsUpChangedListener);
}
@@ -304,6 +310,7 @@ public final class DozeServiceHost implements DozeHost {
if (mAmbientIndicationContainer instanceof DozeReceiver) {
((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
}
+ mBurnInInteractor.dozeTimeTick();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 90a6d0fac7ca..561bd91b964f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -23,10 +23,10 @@ import static com.android.systemui.statusbar.notification.NotificationUtils.inte
import android.content.res.Resources;
import android.util.MathUtils;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView;
@@ -239,7 +239,11 @@ public class KeyguardClockPositionAlgorithm {
}
}
- private int getExpandedPreferredClockY() {
+ /**
+ * give the static topMargin, used for lockscreen clocks to get the initial translationY
+ * to do counter translation
+ */
+ public int getExpandedPreferredClockY() {
if (mIsSplitShade) {
return mSplitShadeTargetTopMargin;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index 9d30cb4c4852..61c1cc82482a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -30,9 +30,9 @@ import android.widget.TextView;
import androidx.annotation.StyleRes;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.keyguard.KeyguardIndication;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 13566ef8c630..720eeba0fd4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -43,9 +43,9 @@ import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index e835c5cebbc3..4d716c206908 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -37,15 +37,15 @@ import androidx.core.animation.Animator;
import androidx.core.animation.AnimatorListenerAdapter;
import androidx.core.animation.ValueAnimator;
+import com.android.app.animation.InterpolatorsAndroidX;
import com.android.keyguard.CarrierTextController;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.R;
-import com.android.systemui.animation.InterpolatorsAndroidX;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.plugins.log.LogLevel;
+import com.android.systemui.log.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeViewStateProvider;
import com.android.systemui.statusbar.CommandQueue;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
index 4839fe6a7bef..5c357d7cd3ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
@@ -20,8 +20,8 @@ import android.util.DisplayMetrics
import android.view.View
import com.android.internal.logging.nano.MetricsProto.MetricsEvent
import com.android.systemui.log.dagger.LSShadeTransitionLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 6bf54430ab38..7bc4fc3c5e47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -24,21 +24,21 @@ import android.os.SystemClock;
import android.util.MathUtils;
import android.util.TimeUtils;
+import com.android.app.animation.Interpolators;
import com.android.systemui.Dumpable;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
/**
* Class to control all aspects about light bar changes.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index cc4f901668ab..46a2457670b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -31,9 +31,9 @@ import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.ViewTreeObserver.OnPreDrawListener;
+import com.android.app.animation.Interpolators;
import com.android.internal.graphics.ColorUtils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 55dc18859c25..560ea8aae594 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -15,11 +15,11 @@ import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.collection.ArrayMap;
+import com.android.app.animation.Interpolators;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index b9a12e28b8ca..bef422ce3004 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -36,10 +36,10 @@ import android.view.animation.Interpolator;
import androidx.annotation.VisibleForTesting;
import androidx.collection.ArrayMap;
+import com.android.app.animation.Interpolators;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -306,7 +306,7 @@ public class NotificationIconContainer extends ViewGroup {
public void applyIconStates() {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
- IconState childState = mIconStates.get(child);
+ ViewState childState = mIconStates.get(child);
if (childState != null) {
childState.applyToView(child);
}
@@ -339,7 +339,6 @@ public class NotificationIconContainer extends ViewGroup {
}
}
if (child instanceof StatusBarIconView) {
- ((StatusBarIconView) child).updateIconDimens();
((StatusBarIconView) child).setDozing(mDozing, false, 0);
}
}
@@ -448,14 +447,9 @@ public class NotificationIconContainer extends ViewGroup {
@VisibleForTesting
boolean isOverflowing(boolean isLastChild, float translationX, float layoutEnd,
float iconSize) {
- if (isLastChild) {
- return translationX + iconSize > layoutEnd;
- } else {
- // If the child is not the last child, we need to ensure that we have room for the next
- // icon and the dot. The dot could be as large as an icon, so verify that we have room
- // for 2 icons.
- return translationX + iconSize * 2f > layoutEnd;
- }
+ // Layout end, as used here, does not include padding end.
+ final float overflowX = isLastChild ? layoutEnd : layoutEnd - iconSize;
+ return translationX >= overflowX;
}
/**
@@ -495,7 +489,10 @@ public class NotificationIconContainer extends ViewGroup {
// First icon to overflow.
if (firstOverflowIndex == -1 && isOverflowing) {
firstOverflowIndex = i;
- mVisualOverflowStart = translationX;
+ mVisualOverflowStart = layoutEnd - mIconSize;
+ if (forceOverflow || mIsStaticLayout) {
+ mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
+ }
}
final float drawingScale = mOnLockScreen && view instanceof StatusBarIconView
? ((StatusBarIconView) view).getIconScaleIncreased()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index 5e5317d764fe..07a6d0a5a470 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -29,7 +29,7 @@ import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
public class SettingsButton extends AlphaOptimizedImageView {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 678873c0165c..a8a834f1e8f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -203,7 +203,8 @@ public interface StatusBarIconController {
@Override
protected LayoutParams onCreateLayoutParams() {
- LinearLayout.LayoutParams lp = super.onCreateLayoutParams();
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
lp.setMargins(mIconHPadding, 0, mIconHPadding, 0);
return lp;
}
@@ -369,7 +370,7 @@ public interface StatusBarIconController {
private final MobileIconsViewModel mMobileIconsViewModel;
protected final Context mContext;
- protected int mIconSize;
+ protected final int mIconSize;
// Whether or not these icons show up in dumpsys
protected boolean mShouldLog = false;
private StatusBarIconController mController;
@@ -394,10 +395,10 @@ public interface StatusBarIconController {
mStatusBarPipelineFlags = statusBarPipelineFlags;
mMobileContextProvider = mobileContextProvider;
mContext = group.getContext();
+ mIconSize = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_icon_size);
mLocation = location;
- reloadDimens();
-
if (statusBarPipelineFlags.runNewMobileIconsBackend()) {
// This starts the flow for the new pipeline, and will notify us of changes if
// {@link StatusBarPipelineFlags#useNewMobileIcons} is also true.
@@ -608,9 +609,13 @@ public interface StatusBarIconController {
mGroup.removeAllViews();
}
- protected void reloadDimens() {
- mIconSize = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_icon_size);
+ protected void onDensityOrFontScaleChanged() {
+ for (int i = 0; i < mGroup.getChildCount(); i++) {
+ View child = mGroup.getChildAt(i);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
+ child.setLayoutParams(lp);
+ }
}
private void setHeightAndCenter(ImageView imageView, int height) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 80d5651a65dc..3a184239ac43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -109,7 +109,6 @@ public class StatusBarIconControllerImpl implements Tunable,
}
group.setController(this);
- group.reloadDimens();
mIconGroups.add(group);
List<Slot> allSlots = mStatusBarIconList.getSlots();
for (int i = 0; i < allSlots.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
index 1f0b96a58da6..12f023b21701 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
@@ -18,11 +18,11 @@ package com.android.systemui.statusbar.phone
import android.app.PendingIntent
import com.android.systemui.log.dagger.NotifInteractionLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.ERROR
-import com.android.systemui.plugins.log.LogLevel.INFO
-import com.android.systemui.plugins.log.LogLevel.WARNING
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.ERROR
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.LogLevel.WARNING
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index ddbfd43f9bf6..26c17674ab10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -22,8 +22,6 @@ import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -74,16 +72,13 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
// Any ignored icon will never be added as a child
private ArrayList<String> mIgnoredSlots = new ArrayList<>();
- private Configuration mConfiguration;
-
public StatusIconContainer(Context context) {
this(context, null);
}
public StatusIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
- mConfiguration = new Configuration(context.getResources().getConfiguration());
- reloadDimens();
+ initDimens();
setWillNotDraw(!DEBUG_OVERFLOW);
}
@@ -100,7 +95,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
return mShouldRestrictIcons;
}
- private void reloadDimens() {
+ private void initDimens() {
// This is the same value that StatusBarIconView uses
mIconDotFrameWidth = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size);
@@ -216,16 +211,6 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
child.setTag(R.id.status_bar_view_state_tag, null);
}
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- final int configDiff = newConfig.diff(mConfiguration);
- mConfiguration.setTo(newConfig);
- if ((configDiff & (ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_FONT_SCALE)) != 0) {
- reloadDimens();
- }
- }
-
/**
* Add a name of an icon slot to be ignored. It will not show up nor be measured
* @param slotName name of the icon as it exists in
@@ -363,17 +348,13 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
int totalVisible = mLayoutStates.size();
int maxVisible = totalVisible <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1;
- // Init mUnderflowStart value with the offset to let the dot be placed next to battery icon.
- // It to prevent if the underflow happens at rightest(totalVisible - 1) child then break the
- // for loop with mUnderflowStart staying 0(initial value), causing the dot be placed at the
- // leftest side.
- mUnderflowStart = (int) Math.max(contentStart, width - getPaddingEnd() - mUnderflowWidth);
+ mUnderflowStart = 0;
int visible = 0;
int firstUnderflowIndex = -1;
for (int i = totalVisible - 1; i >= 0; i--) {
StatusIconState state = mLayoutStates.get(i);
// Allow room for underflow if we found we need it in onMeasure
- if ((mNeedsUnderflow && (state.getXTranslation() < (contentStart + mUnderflowWidth)))
+ if (mNeedsUnderflow && (state.getXTranslation() < (contentStart + mUnderflowWidth))
|| (mShouldRestrictIcons && (visible >= maxVisible))) {
firstUnderflowIndex = i;
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 8fa803ea3a8f..cdf66526ab63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -15,7 +15,7 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
import com.android.systemui.DejankUtils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 453dd1bb6f81..5af8932859c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -14,11 +14,7 @@
package com.android.systemui.statusbar.phone.fragment;
-import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
-import static android.app.StatusBarManager.DISABLE_CLOCK;
-import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
-import static android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP;
-import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
+
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
@@ -44,10 +40,10 @@ import android.widget.LinearLayout;
import androidx.annotation.VisibleForTesting;
import androidx.core.animation.Animator;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
@@ -112,8 +108,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private View mClockView;
private View mOngoingCallChip;
private View mNotificationIconAreaInner;
- private int mDisabled1;
- private int mDisabled2;
+ // Visibilities come in from external system callers via disable flags, but we also sometimes
+ // modify the visibilities internally. We need to store both so that we don't accidentally
+ // propagate our internally modified flags for too long.
+ private StatusBarVisibilityModel mLastSystemVisibility =
+ StatusBarVisibilityModel.createDefaultModel();
+ private StatusBarVisibilityModel mLastModifiedVisibility =
+ StatusBarVisibilityModel.createDefaultModel();
private DarkIconManager mDarkIconManager;
private final StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory;
private final CommandQueue mCommandQueue;
@@ -141,7 +142,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private final OngoingCallListener mOngoingCallListener = new OngoingCallListener() {
@Override
public void onOngoingCallStateChanged(boolean animate) {
- disable(getContext().getDisplayId(), mDisabled1, mDisabled2, animate);
+ updateStatusBarVisibilities(animate);
}
};
private OperatorNameViewController mOperatorNameViewController;
@@ -388,8 +389,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
notificationIconArea.addView(mNotificationIconAreaInner);
- // #disable should have already been called, so use the disable values to set visibility.
- updateNotificationIconAreaAndCallChip(mDisabled1, false);
+ updateNotificationIconAreaAndCallChip(/* animate= */ false);
}
/**
@@ -408,49 +408,50 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
if (displayId != getContext().getDisplayId()) {
return;
}
+ mCollapsedStatusBarFragmentLogger
+ .logDisableFlagChange(new DisableState(state1, state2));
+ mLastSystemVisibility =
+ StatusBarVisibilityModel.createModelFromFlags(state1, state2);
+ updateStatusBarVisibilities(animate);
+ }
- int state1BeforeAdjustment = state1;
- state1 = adjustDisableFlags(state1);
-
- mCollapsedStatusBarFragmentLogger.logDisableFlagChange(
- /* new= */ new DisableState(state1BeforeAdjustment, state2),
- /* newAfterLocalModification= */ new DisableState(state1, state2));
-
- final int old1 = mDisabled1;
- final int diff1 = state1 ^ old1;
- final int old2 = mDisabled2;
- final int diff2 = state2 ^ old2;
- mDisabled1 = state1;
- mDisabled2 = state2;
- if ((diff1 & DISABLE_SYSTEM_INFO) != 0 || ((diff2 & DISABLE2_SYSTEM_ICONS) != 0)) {
- if ((state1 & DISABLE_SYSTEM_INFO) != 0 || ((state2 & DISABLE2_SYSTEM_ICONS) != 0)) {
- hideEndSideContent(animate);
- hideOperatorName(animate);
- } else {
+ private void updateStatusBarVisibilities(boolean animate) {
+ StatusBarVisibilityModel previousModel = mLastModifiedVisibility;
+ StatusBarVisibilityModel newModel = calculateInternalModel(mLastSystemVisibility);
+ mCollapsedStatusBarFragmentLogger.logVisibilityModel(newModel);
+ mLastModifiedVisibility = newModel;
+
+ if (newModel.getShowSystemInfo() != previousModel.getShowSystemInfo()) {
+ if (newModel.getShowSystemInfo()) {
showEndSideContent(animate);
showOperatorName(animate);
+ } else {
+ hideEndSideContent(animate);
+ hideOperatorName(animate);
}
}
// The ongoing call chip and notification icon visibilities are intertwined, so update both
// if either change.
- if (((diff1 & DISABLE_ONGOING_CALL_CHIP) != 0)
- || ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0)) {
- updateNotificationIconAreaAndCallChip(state1, animate);
+ if (newModel.getShowNotificationIcons() != previousModel.getShowNotificationIcons()
+ || newModel.getShowOngoingCallChip() != previousModel.getShowOngoingCallChip()) {
+ updateNotificationIconAreaAndCallChip(animate);
}
// The clock may have already been hidden, but we might want to shift its
// visibility to GONE from INVISIBLE or vice versa
- if ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) {
- if ((state1 & DISABLE_CLOCK) != 0) {
- hideClock(animate);
- } else {
+ if (newModel.getShowClock() != previousModel.getShowClock()
+ || mClockView.getVisibility() != clockHiddenMode()) {
+ if (newModel.getShowClock()) {
showClock(animate);
+ } else {
+ hideClock(animate);
}
}
}
- protected int adjustDisableFlags(int state) {
+ private StatusBarVisibilityModel calculateInternalModel(
+ StatusBarVisibilityModel externalModel) {
boolean headsUpVisible =
mStatusBarFragmentComponent.getHeadsUpAppearanceController().shouldBeVisible();
@@ -459,34 +460,31 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
&& shouldHideNotificationIcons()
&& !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD
&& headsUpVisible)) {
- state |= DISABLE_NOTIFICATION_ICONS;
- state |= DISABLE_SYSTEM_INFO;
- state |= DISABLE_CLOCK;
- }
-
- if (mOngoingCallController.hasOngoingCall()) {
- state &= ~DISABLE_ONGOING_CALL_CHIP;
- } else {
- state |= DISABLE_ONGOING_CALL_CHIP;
- }
-
- if (headsUpVisible) {
- // Disable everything on the left side of the status bar, since the app name for the
- // heads up notification appears there instead.
- state |= DISABLE_CLOCK;
- state |= DISABLE_ONGOING_CALL_CHIP;
+ // Hide everything
+ return new StatusBarVisibilityModel(
+ /* showClock= */ false,
+ /* showNotificationIcons= */ false,
+ /* showOngoingCallChip= */ false,
+ /* showSystemInfo= */ false);
}
- return state;
+ boolean showClock = externalModel.getShowClock() && !headsUpVisible;
+ boolean showOngoingCallChip = mOngoingCallController.hasOngoingCall() && !headsUpVisible;
+ return new StatusBarVisibilityModel(
+ showClock,
+ externalModel.getShowNotificationIcons(),
+ showOngoingCallChip,
+ externalModel.getShowSystemInfo());
}
/**
* Updates the visibility of the notification icon area and ongoing call chip based on disabled1
* state.
*/
- private void updateNotificationIconAreaAndCallChip(int state1, boolean animate) {
- boolean disableNotifications = (state1 & DISABLE_NOTIFICATION_ICONS) != 0;
- boolean hasOngoingCall = (state1 & DISABLE_ONGOING_CALL_CHIP) == 0;
+ private void updateNotificationIconAreaAndCallChip(boolean animate) {
+ StatusBarVisibilityModel visibilityModel = mLastModifiedVisibility;
+ boolean disableNotifications = !visibilityModel.getShowNotificationIcons();
+ boolean hasOngoingCall = visibilityModel.getShowOngoingCallChip();
// Hide notifications if the disable flag is set or we have an ongoing call.
if (disableNotifications || hasOngoingCall) {
@@ -683,7 +681,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
@Override
public void onDozingChanged(boolean isDozing) {
- disable(getContext().getDisplayId(), mDisabled1, mDisabled2, false /* animate */);
+ updateStatusBarVisibilities(/* animate= */ false);
}
@Nullable
@@ -698,10 +696,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
}
- private boolean isSystemIconAreaDisabled() {
- return (mDisabled1 & DISABLE_SYSTEM_INFO) != 0 || (mDisabled2 & DISABLE2_SYSTEM_ICONS) != 0;
- }
-
private void updateStatusBarLocation(int left, int right) {
int leftMargin = left - mStatusBar.getLeft();
int rightMargin = mStatusBar.getRight() - right;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
index d64bc58a0c37..8c19fb4f43c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.phone.fragment
import com.android.systemui.log.dagger.CollapsedSbFragmentLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import javax.inject.Inject
@@ -37,7 +37,6 @@ class CollapsedStatusBarFragmentLogger @Inject constructor(
*/
fun logDisableFlagChange(
new: DisableFlagsLogger.DisableState,
- newAfterLocalModification: DisableFlagsLogger.DisableState
) {
buffer.log(
TAG,
@@ -45,19 +44,34 @@ class CollapsedStatusBarFragmentLogger @Inject constructor(
{
int1 = new.disable1
int2 = new.disable2
- long1 = newAfterLocalModification.disable1.toLong()
- long2 = newAfterLocalModification.disable2.toLong()
},
{
disableFlagsLogger.getDisableFlagsString(
old = null,
new = DisableFlagsLogger.DisableState(int1, int2),
- newAfterLocalModification =
- DisableFlagsLogger.DisableState(long1.toInt(), long2.toInt())
)
}
)
}
+
+ fun logVisibilityModel(model: StatusBarVisibilityModel) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ bool1 = model.showClock
+ bool2 = model.showNotificationIcons
+ bool3 = model.showOngoingCallChip
+ bool4 = model.showSystemInfo
+ },
+ { "New visibilities calculated internally. " +
+ "showClock=$bool1 " +
+ "showNotificationIcons=$bool2 " +
+ "showOngoingCallChip=$bool3 " +
+ "showSystemInfo=$bool4"
+ }
+ )
+ }
}
private const val TAG = "CollapsedSbFragment"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
new file mode 100644
index 000000000000..cf54cb7aa954
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.fragment
+
+import android.app.StatusBarManager.DISABLE2_NONE
+import android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS
+import android.app.StatusBarManager.DISABLE_CLOCK
+import android.app.StatusBarManager.DISABLE_NONE
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
+import android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP
+import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
+
+/** A model for which parts of the status bar should be visible or not visible. */
+data class StatusBarVisibilityModel(
+ val showClock: Boolean,
+ val showNotificationIcons: Boolean,
+ val showOngoingCallChip: Boolean,
+ val showSystemInfo: Boolean,
+) {
+ companion object {
+ /** Creates the default model. */
+ @JvmStatic
+ fun createDefaultModel(): StatusBarVisibilityModel {
+ return createModelFromFlags(DISABLE_NONE, DISABLE2_NONE)
+ }
+
+ /**
+ * Given a set of disabled flags, converts them into the correct visibility statuses.
+ *
+ * See [CommandQueue.Callbacks.disable].
+ */
+ @JvmStatic
+ fun createModelFromFlags(disabled1: Int, disabled2: Int): StatusBarVisibilityModel {
+ return StatusBarVisibilityModel(
+ showClock = (disabled1 and DISABLE_CLOCK) == 0,
+ showNotificationIcons = (disabled1 and DISABLE_NOTIFICATION_ICONS) == 0,
+ // TODO(b/279899176): [CollapsedStatusBarFragment] always overwrites this with the
+ // value of [OngoingCallController]. Do we need to process the flag here?
+ showOngoingCallChip = (disabled1 and DISABLE_ONGOING_CALL_CHIP) == 0,
+ showSystemInfo =
+ (disabled1 and DISABLE_SYSTEM_INFO) == 0 &&
+ (disabled2 and DISABLE2_SYSTEM_ICONS) == 0
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index b3d246164e87..19c77e0b0de3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -22,7 +22,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
-import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.log.LogBuffer
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepositoryImpl
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
index 68cbbceb056d..b3a1c4075d87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
@@ -22,8 +22,8 @@ import android.telephony.TelephonyDisplayInfo
import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.MobileInputLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
index f2f91430eba6..7e0c145696c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
@@ -20,8 +20,8 @@ import android.view.View
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.MobileViewLog
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
index f67bc8f14447..507549b1e234 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
@@ -19,8 +19,8 @@ package com.android.systemui.statusbar.pipeline.mobile.ui
import android.view.View
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.VerboseMobileViewLog
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger.Companion.getIdForLogging
import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
index 82492babba46..051f43f1059c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
@@ -19,8 +19,8 @@ package com.android.systemui.statusbar.pipeline.shared
import android.net.Network
import android.net.NetworkCapabilities
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.SharedConnectivityInputLog
import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
index a96e8ff20dd4..328d901b541d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
@@ -18,8 +18,8 @@ package com.android.systemui.statusbar.pipeline.shared
import android.net.Network
import android.net.NetworkCapabilities
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
/** Helper object for logs that are shared between wifi and mobile. */
object LoggerHelper {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt
index 2a02687f0761..058eda4400df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.shared.data.model
import android.net.NetworkCapabilities
-import com.android.systemui.plugins.log.LogMessage
+import com.android.systemui.log.LogMessage
/**
* A model for all of the current default connections(s).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
index bb0b166f7aba..4a9ceacb0bd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
@@ -19,8 +19,8 @@ package com.android.systemui.statusbar.pipeline.wifi.shared
import android.net.Network
import android.net.NetworkCapabilities
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.WifiInputLog
import com.android.systemui.statusbar.pipeline.shared.LoggerHelper
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
index f61f3b7a70f0..6ba2a81b4b13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
@@ -21,9 +21,9 @@ import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED
import com.android.internal.R
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.VERBOSE
import com.android.systemui.log.dagger.DeviceStateAutoRotationLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.VERBOSE
import javax.inject.Inject
class DeviceStateRotationLockSettingControllerLogger
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
index df1e80b78c9b..06ed1fd279b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.statusbar.policy
import com.android.systemui.log.dagger.NotificationHeadsUpLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.INFO
-import com.android.systemui.plugins.log.LogLevel.VERBOSE
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.LogLevel.VERBOSE
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
index 4dd63be47735..e1ec94fada81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
@@ -24,9 +24,9 @@ import android.view.View;
import androidx.core.graphics.ColorUtils;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardConstants;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.qs.tiles.UserDetailItemView;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 928e0115287d..66b52563c0a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -31,6 +31,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardConstants;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -38,7 +39,6 @@ import com.android.keyguard.KeyguardVisibilityHelper;
import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
index 850a4b499562..363b06ab780b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
@@ -21,11 +21,11 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.keyguard.KeyguardConstants;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
-import com.android.systemui.animation.Interpolators;
/**
* The container for the user switcher on Keyguard.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 403a7e8116c8..e311bad9e865 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -73,6 +73,7 @@ import androidx.core.animation.AnimatorSet;
import androidx.core.animation.ObjectAnimator;
import androidx.core.animation.ValueAnimator;
+import com.android.app.animation.InterpolatorsAndroidX;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.logging.UiEvent;
@@ -80,7 +81,6 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.animation.InterpolatorsAndroidX;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
index b563d86f65b1..21d03386b9e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
@@ -311,7 +311,7 @@ interface SmartActionInflater {
setBounds(0, 0, newIconSize, newIconSize)
}
// Add the action icon to the Smart Action button.
- setCompoundDrawables(iconDrawable, null, null, null)
+ setCompoundDrawablesRelative(iconDrawable, null, null, null)
val onClickListener = View.OnClickListener {
onSmartActionClick(entry, smartActions, actionIndex, action)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 9e88ceb3a0d1..fb6ba8542a3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -588,15 +588,15 @@ public class SmartReplyView extends ViewGroup {
}
/**
- * Returns the combined width of the left drawable (the action icon) and the padding between the
- * drawable and the button text.
+ * Returns the combined width of the start drawable (the action icon) and the padding between
+ * the drawable and the button text.
*/
- private int getLeftCompoundDrawableWidthWithPadding(Button button) {
- Drawable[] drawables = button.getCompoundDrawables();
- Drawable leftDrawable = drawables[0];
- if (leftDrawable == null) return 0;
+ private int getStartCompoundDrawableWidthWithPadding(Button button) {
+ Drawable[] drawables = button.getCompoundDrawablesRelative();
+ Drawable startDrawable = drawables[0];
+ if (startDrawable == null) return 0;
- return leftDrawable.getBounds().width() + button.getCompoundDrawablePadding();
+ return startDrawable.getBounds().width() + button.getCompoundDrawablePadding();
}
private int squeezeButtonToTextWidth(Button button, int heightMeasureSpec, int textWidth) {
@@ -605,8 +605,8 @@ public class SmartReplyView extends ViewGroup {
// Re-measure the squeezed smart reply button.
clearLayoutLineCount(button);
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- button.getPaddingLeft() + button.getPaddingRight() + textWidth
- + getLeftCompoundDrawableWidthWithPadding(button), MeasureSpec.AT_MOST);
+ button.getPaddingStart() + button.getPaddingEnd() + textWidth
+ + getStartCompoundDrawableWidthWithPadding(button), MeasureSpec.AT_MOST);
button.measure(widthMeasureSpec, heightMeasureSpec);
if (button.getLayout() == null) {
Log.wtf(TAG, "Button layout is null after measure.");
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
index 667e22a82a2a..066ac04c2727 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.temporarydisplay
import android.view.View
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
/** A logger for temporary view changes -- see [TemporaryViewDisplayController]. */
open class TemporaryViewLogger<T : TemporaryViewInfo>(
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
index 16123882046c..46954b5b81ef 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
@@ -18,7 +18,7 @@ package com.android.systemui.temporarydisplay.chipbar
import android.view.View
import android.view.ViewGroup
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.animation.ViewHierarchyAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.children
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
index e819f946a6d6..4fbbc8915c19 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
@@ -34,10 +34,10 @@ import android.widget.TextView
import androidx.annotation.DimenRes
import androidx.annotation.IdRes
import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
import com.android.internal.widget.CachingIconView
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
import com.android.systemui.common.shared.model.Text.Companion.loadText
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
index f23942847e68..d55751b9d8a0 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.temporarydisplay.chipbar
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import com.android.systemui.temporarydisplay.TemporaryViewLogger
import com.android.systemui.temporarydisplay.dagger.ChipbarLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
index b1be4045eb43..cae13086f592 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
@@ -18,9 +18,9 @@ package com.android.systemui.temporarydisplay.dagger
import android.content.Context
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.media.taptotransfer.MediaTttFlags
-import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.settings.DisplayTracker
import com.android.systemui.statusbar.gesture.SwipeUpGestureLogger
import com.android.systemui.temporarydisplay.chipbar.SwipeChipbarAwayGestureHandler
diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
index f0fa779ba0cf..58f22466d44d 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
@@ -51,6 +51,7 @@ class DynamicColors {
Pair.create("surface_variant", MDC.surfaceVariant()),
Pair.create("on_surface_variant", MDC.onSurfaceVariant()),
Pair.create("outline", MDC.outline()),
+ Pair.create("outline_variant", MDC.outlineVariant()),
Pair.create("error", MDC.error()),
Pair.create("on_error", MDC.onError()),
Pair.create("error_container", MDC.errorContainer()),
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 43d15bcc22b3..4b73d6190d99 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -659,6 +659,10 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
== mColorScheme.getNeutral1().getS500()
&& res.getColor(android.R.color.system_neutral2_500, theme)
== mColorScheme.getNeutral2().getS500()
+ && res.getColor(android.R.color.system_outline_variant_dark, theme)
+ == MaterialDynamicColors.outlineVariant().getArgb(mDynamicSchemeDark)
+ && res.getColor(android.R.color.system_outline_variant_light, theme)
+ == MaterialDynamicColors.outlineVariant().getArgb(mDynamicSchemeLight)
&& res.getColor(android.R.color.system_primary_container_dark, theme)
== MaterialDynamicColors.primaryContainer().getArgb(mDynamicSchemeDark)
&& res.getColor(android.R.color.system_primary_container_light, theme)
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
index fda511433143..dfe748afbd41 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
@@ -17,10 +17,10 @@
package com.android.systemui.toast
import com.android.systemui.log.dagger.ToastLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogMessage
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogMessage
import javax.inject.Inject
private const val TAG = "ToastLog"
diff --git a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
index eb23b9d7a994..d940a6b5c460 100644
--- a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
+++ b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
@@ -16,8 +16,6 @@
syntax = "proto2";
-import "frameworks/base/libs/WindowManager/Shell/proto/wm_shell_trace.proto";
-
package com.android.systemui.tracing;
option java_multiple_files = true;
@@ -25,7 +23,6 @@ option java_multiple_files = true;
message SystemUiTraceProto {
optional EdgeBackGestureHandlerProto edge_back_gesture_handler = 1;
- optional com.android.wm.shell.WmShellTraceProto wm_shell = 2;
}
message EdgeBackGestureHandlerProto {
diff --git a/packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt b/packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt
index 27a53bf2ceda..41b3145ed36e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt
@@ -19,6 +19,7 @@ package com.android.systemui.util
import android.content.res.TypedArray
import android.graphics.Color
import android.view.ContextThemeWrapper
+import androidx.annotation.ColorInt
/** Returns an ARGB color version of [color] at the given [alpha]. */
fun getColorWithAlpha(color: Int, alpha: Float): Int =
@@ -35,8 +36,11 @@ fun getColorWithAlpha(color: Int, alpha: Float): Int =
* otherwise, returns the color from the private attribute {@param privAttrId}.
*/
fun getPrivateAttrColorIfUnset(
- ctw: ContextThemeWrapper, attrArray: TypedArray,
- attrIndex: Int, defColor: Int, privAttrId: Int
+ ctw: ContextThemeWrapper,
+ attrArray: TypedArray,
+ attrIndex: Int,
+ defColor: Int,
+ privAttrId: Int
): Int {
// If the index is specified, use that value
var a = attrArray
@@ -51,3 +55,8 @@ fun getPrivateAttrColorIfUnset(
a.recycle()
return color
}
+
+/** Returns the color as a HTML hex color (or null) */
+fun hexColorString(@ColorInt color: Int?): String = color
+ ?.let { String.format("#%08x", it) }
+ ?: "null"
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
index 5d8029293107..db4ab7edbcf1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
@@ -19,7 +19,7 @@ package com.android.systemui.util.animation
import android.animation.ValueAnimator
import android.graphics.PointF
import android.util.MathUtils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
/**
* The fraction after which we start fading in when going from a gone widget to a visible one
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java
index 59cb0525a7e9..9cebc330af12 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java
@@ -18,7 +18,7 @@ package com.android.systemui.util.wakelock;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt
index 951903dc29bd..09268007dddc 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.util.wakelock
import android.os.PowerManager
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
import javax.inject.Inject
class WakeLockLogger @Inject constructor(@WakeLockLog private val buffer: LogBuffer) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/wrapper/DisplayUtilsWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/DisplayUtilsWrapper.kt
new file mode 100644
index 000000000000..cfca7f9da686
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/DisplayUtilsWrapper.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.wrapper
+
+import android.util.DisplayUtils
+import android.view.Display
+import javax.inject.Inject
+
+/** Injectable wrapper around `DisplayUtils` functions */
+class DisplayUtilsWrapper @Inject constructor() {
+ fun getPhysicalPixelDisplaySizeRatio(
+ physicalWidth: Int,
+ physicalHeight: Int,
+ currentWidth: Int,
+ currentHeight: Int
+ ): Float {
+ return DisplayUtils.getPhysicalPixelDisplaySizeRatio(
+ physicalWidth,
+ physicalHeight,
+ currentWidth,
+ currentHeight
+ )
+ }
+
+ fun getMaximumResolutionDisplayMode(modes: Array<Display.Mode>?): Display.Mode? {
+ return DisplayUtils.getMaximumResolutionDisplayMode(modes)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 77210b78832b..91078dc65477 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -109,6 +109,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -119,7 +120,6 @@ import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index e60f9b65dc1c..5144d1966222 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -362,9 +362,6 @@ public final class WMShell implements
@Override
public void writeToProto(SystemUiTraceProto proto) {
- if (proto.wmShell == null) {
- proto.wmShell = new WmShellTraceProto();
- }
// Dump to WMShell proto here
// TODO: Figure out how we want to synchronize while dumping to proto
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 8f4b32006919..19d5278932c2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -35,7 +35,7 @@ import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockFaceConfig
import com.android.systemui.plugins.ClockFaceEvents
import com.android.systemui.plugins.ClockTickRate
-import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.log.LogBuffer
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 95db0c096faf..fb738454fc71 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -45,6 +45,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.log.LogBuffer;
import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.plugins.ClockEvents;
@@ -52,7 +53,6 @@ import com.android.systemui.plugins.ClockFaceConfig;
import com.android.systemui.plugins.ClockFaceController;
import com.android.systemui.plugins.ClockFaceEvents;
import com.android.systemui.plugins.ClockTickRate;
-import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.shared.clocks.ClockRegistry;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 2962c14b813a..ddd9a084bbd2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -151,7 +151,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
+import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.internal.util.reflection.FieldSetter;
@@ -2737,6 +2739,36 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
verifyFingerprintAuthenticateCall();
}
+ @Test
+ public void onTrustChangedCallbacksCalledBeforeOnTrustGrantedForCurrentUserCallback() {
+ // GIVEN device is interactive
+ deviceIsInteractive();
+
+ // GIVEN callback is registered
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ // WHEN onTrustChanged enabled=true
+ mKeyguardUpdateMonitor.onTrustChanged(
+ true /* enabled */,
+ true /* newlyUnlocked */,
+ getCurrentUser() /* userId */,
+ TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD /* flags */,
+ null /* trustGrantedMessages */);
+
+ // THEN onTrustChanged is called FIRST
+ final InOrder inOrder = Mockito.inOrder(callback);
+ inOrder.verify(callback).onTrustChanged(eq(getCurrentUser()));
+
+ // AND THEN onTrustGrantedForCurrentUser callback called
+ inOrder.verify(callback).onTrustGrantedForCurrentUser(
+ eq(true) /* dismissKeyguard */,
+ eq(true) /* newlyUnlocked */,
+ eq(new TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD)),
+ eq(null) /* message */
+ );
+ }
+
private void verifyFingerprintAuthenticateNeverCalled() {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any());
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
deleted file mode 100644
index 2c680be97e95..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.animation
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import java.lang.reflect.Modifier
-import junit.framework.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@SmallTest
-@RunWith(JUnit4::class)
-class InterpolatorsAndroidXTest : SysuiTestCase() {
-
- @Test
- fun testInterpolatorsAndInterpolatorsAndroidXPublicMethodsAreEqual() {
- assertEquals(
- Interpolators::class.java.getPublicMethods(),
- InterpolatorsAndroidX::class.java.getPublicMethods()
- )
- }
-
- @Test
- fun testInterpolatorsAndInterpolatorsAndroidXPublicFieldsAreEqual() {
- assertEquals(
- Interpolators::class.java.getPublicFields(),
- InterpolatorsAndroidX::class.java.getPublicFields()
- )
- }
-
- private fun <T> Class<T>.getPublicMethods() =
- declaredMethods
- .filter { Modifier.isPublic(it.modifiers) }
- .map { it.toString().replace(name, "") }
- .toSet()
-
- private fun <T> Class<T>.getPublicFields() =
- fields.filter { Modifier.isPublic(it.modifiers) }.map { it.name }.toSet()
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
index d7aa6e063d1e..14ad3acf7fb0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
@@ -39,10 +39,6 @@ import org.mockito.Mockito.verify
import kotlin.math.ceil
-private val PAINT = TextPaint().apply {
- textSize = 32f
-}
-
@RunWith(AndroidTestingRunner::class)
@SmallTest
class TextAnimatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
index 063757acc1a1..f6fcd16cfd00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
@@ -49,7 +49,7 @@ private val VF_FONT = Font.Builder(File("/system/fonts/Roboto-Regular.ttf")).bui
private fun Font.toTypeface() =
Typeface.CustomFallbackBuilder(FontFamily.Builder(this).build()).build()
-private val PAINT = TextPaint().apply {
+internal val PAINT = TextPaint().apply {
typeface = Font.Builder(VF_FONT).setFontVariationSettings("'wght' 400").build().toTypeface()
textSize = 32f
}
@@ -79,7 +79,7 @@ class TextInterpolatorTest : SysuiTestCase() {
@Before
fun setup() {
- typefaceCache = TypefaceVariantCacheImpl()
+ typefaceCache = TypefaceVariantCacheImpl(PAINT.typeface)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
index 6ab54a374d30..da9ceb47446a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -19,6 +19,7 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import com.android.app.animation.Interpolators
@SmallTest
@RunWith(AndroidTestingRunner::class)
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 6e37ee791bd2..a361bbc69ef3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -68,7 +68,6 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
-@Ignore("b/279650412")
@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
@@ -281,6 +280,7 @@ class AuthContainerViewTest : SysuiTestCase() {
assertThat(authContainer!!.parent).isNull()
}
+ @Ignore("b/279650412")
@Test
fun testActionUseDeviceCredential_sendsOnDeviceCredentialPressed() {
val container = initializeFingerprintContainer(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 2747e83acb23..8a62ea0d669e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -25,7 +25,6 @@ import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROL
import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
-import androidx.test.ext.junit.runners.AndroidJUnit4
import android.testing.TestableLooper.RunWithLooper
import android.view.LayoutInflater
import android.view.MotionEvent
@@ -35,6 +34,7 @@ import android.view.Surface.Rotation
import android.view.View
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.settingslib.udfps.UdfpsOverlayParams
@@ -69,8 +69,8 @@ import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
private const val REQUEST_ID = 2L
@@ -340,4 +340,22 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
assertThat(lp.height).isEqualTo(overlayParams.sensorBounds.height())
}
}
+
+ @Test
+ fun fullScreenOverlayWithNewTouchDetectionEnabled() = withRotation(ROTATION_0) {
+ withReason(REASON_AUTH_KEYGUARD) {
+ whenever(featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true)
+
+ controllerOverlay.show(udfpsController, overlayParams)
+ verify(windowManager).addView(
+ eq(controllerOverlay.overlayView),
+ layoutParamsCaptor.capture()
+ )
+
+ // Layout params should use natural display width and height
+ val lp = layoutParamsCaptor.value
+ assertThat(lp.width).isEqualTo(overlayParams.naturalDisplayWidth)
+ assertThat(lp.height).isEqualTo(overlayParams.naturalDisplayHeight)
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt
new file mode 100644
index 000000000000..21516d4917b5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.clipboardoverlay
+
+import android.content.ContentResolver
+import android.content.Context
+import android.net.Uri
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.whenever
+import java.io.IOException
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertNull
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class ClipboardImageLoaderTest : SysuiTestCase() {
+ @Mock private lateinit var mockContext: Context
+
+ @Mock private lateinit var mockContentResolver: ContentResolver
+
+ private lateinit var clipboardImageLoader: ClipboardImageLoader
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ @Throws(IOException::class)
+ fun test_imageLoadSuccess() = runTest {
+ val testDispatcher = StandardTestDispatcher(this.testScheduler)
+ clipboardImageLoader =
+ ClipboardImageLoader(mockContext, testDispatcher, CoroutineScope(testDispatcher))
+ val testUri = Uri.parse("testUri")
+ whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
+ whenever(mockContext.resources).thenReturn(context.resources)
+
+ clipboardImageLoader.load(testUri)
+
+ verify(mockContentResolver).loadThumbnail(eq(testUri), any(), any())
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ @Throws(IOException::class)
+ fun test_imageLoadFailure() = runTest {
+ val testDispatcher = StandardTestDispatcher(this.testScheduler)
+ clipboardImageLoader =
+ ClipboardImageLoader(mockContext, testDispatcher, CoroutineScope(testDispatcher))
+ val testUri = Uri.parse("testUri")
+ whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
+ whenever(mockContext.resources).thenReturn(context.resources)
+
+ val res = clipboardImageLoader.load(testUri)
+
+ verify(mockContentResolver).loadThumbnail(eq(testUri), any(), any())
+ assertNull(res)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index fe5fa1fdd39f..39fb7b4cda2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -25,6 +25,7 @@ import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBO
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_EXPANDED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_MINIMIZED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
+import static com.android.systemui.flags.Flags.CLIPBOARD_IMAGE_TIMEOUT;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -90,6 +91,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Mock
private ClipboardOverlayUtils mClipboardUtils;
@Mock
+ private ClipboardImageLoader mClipboardImageLoader;
+ @Mock
private UiEventLogger mUiEventLogger;
private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
@@ -120,6 +123,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
mSampleClipData = new ClipData("Test", new String[]{"text/plain"},
new ClipData.Item("Test Item"));
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, true); // turned off for legacy tests
mOverlayController = new ClipboardOverlayController(
mContext,
@@ -131,6 +135,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
mFeatureFlags,
mClipboardUtils,
mExecutor,
+ mClipboardImageLoader,
mUiEventLogger);
verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture());
mCallbacks = mOverlayCallbacksCaptor.getValue();
@@ -142,6 +147,69 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
}
@Test
+ public void test_setClipData_invalidImageData_legacy() {
+ ClipData clipData = new ClipData("", new String[]{"image/png"},
+ new ClipData.Item(Uri.parse("")));
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+
+ mOverlayController.setClipData(clipData, "");
+
+ verify(mClipboardOverlayView, times(1)).showDefaultTextPreview();
+ verify(mClipboardOverlayView, times(1)).showShareChip();
+ verify(mClipboardOverlayView, times(1)).getEnterAnimation();
+ }
+
+ @Test
+ public void test_setClipData_nonImageUri_legacy() {
+ ClipData clipData = new ClipData("", new String[]{"resource/png"},
+ new ClipData.Item(Uri.parse("")));
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+
+ mOverlayController.setClipData(clipData, "");
+
+ verify(mClipboardOverlayView, times(1)).showDefaultTextPreview();
+ verify(mClipboardOverlayView, times(1)).showShareChip();
+ verify(mClipboardOverlayView, times(1)).getEnterAnimation();
+ }
+
+ @Test
+ public void test_setClipData_textData_legacy() {
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+ mOverlayController.setClipData(mSampleClipData, "abc");
+
+ verify(mClipboardOverlayView, times(1)).showTextPreview("Test Item", false);
+ verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SHOWN_EXPANDED, 0, "abc");
+ verify(mClipboardOverlayView, times(1)).showShareChip();
+ verify(mClipboardOverlayView, times(1)).getEnterAnimation();
+ }
+
+ @Test
+ public void test_setClipData_sensitiveTextData_legacy() {
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+ ClipDescription description = mSampleClipData.getDescription();
+ PersistableBundle b = new PersistableBundle();
+ b.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
+ description.setExtras(b);
+ ClipData data = new ClipData(description, mSampleClipData.getItemAt(0));
+ mOverlayController.setClipData(data, "");
+
+ verify(mClipboardOverlayView, times(1)).showTextPreview("••••••", true);
+ verify(mClipboardOverlayView, times(1)).showShareChip();
+ verify(mClipboardOverlayView, times(1)).getEnterAnimation();
+ }
+
+ @Test
+ public void test_setClipData_repeatedCalls_legacy() {
+ when(mAnimator.isRunning()).thenReturn(true);
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+
+ mOverlayController.setClipData(mSampleClipData, "");
+ mOverlayController.setClipData(mSampleClipData, "");
+
+ verify(mClipboardOverlayView, times(1)).getEnterAnimation();
+ }
+
+ @Test
public void test_setClipData_invalidImageData() {
ClipData clipData = new ClipData("", new String[]{"image/png"},
new ClipData.Item(Uri.parse("")));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt
new file mode 100644
index 000000000000..a308c8ee38ca
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.common.ui.data.repository
+
+import android.content.res.Configuration
+import android.view.Display
+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.statusbar.policy.ConfigurationController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.wrapper.DisplayUtilsWrapper
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ConfigurationRepositoryImplTest : SysuiTestCase() {
+ private var displaySizeRatio = 0f
+ @Mock private lateinit var configurationController: ConfigurationController
+ @Mock private lateinit var displayUtils: DisplayUtilsWrapper
+
+ private lateinit var testScope: TestScope
+ private lateinit var underTest: ConfigurationRepositoryImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ setPhysicalPixelDisplaySizeRatio(displaySizeRatio)
+
+ testScope = TestScope()
+ underTest =
+ ConfigurationRepositoryImpl(
+ configurationController,
+ context,
+ testScope.backgroundScope,
+ displayUtils,
+ )
+ }
+
+ @Test
+ fun onAnyConfigurationChange_updatesOnUiModeChanged() =
+ testScope.runTest {
+ val lastAnyConfigurationChange by collectLastValue(underTest.onAnyConfigurationChange)
+ assertThat(lastAnyConfigurationChange).isNull()
+
+ val configurationCallback = withArgCaptor {
+ verify(configurationController).addCallback(capture())
+ }
+
+ configurationCallback.onUiModeChanged()
+ runCurrent()
+ assertThat(lastAnyConfigurationChange).isNotNull()
+ }
+
+ @Test
+ fun onAnyConfigurationChange_updatesOnThemeChanged() =
+ testScope.runTest {
+ val lastAnyConfigurationChange by collectLastValue(underTest.onAnyConfigurationChange)
+ assertThat(lastAnyConfigurationChange).isNull()
+
+ val configurationCallback = withArgCaptor {
+ verify(configurationController).addCallback(capture())
+ }
+
+ configurationCallback.onThemeChanged()
+ runCurrent()
+ assertThat(lastAnyConfigurationChange).isNotNull()
+ }
+
+ @Test
+ fun onAnyConfigurationChange_updatesOnConfigChanged() =
+ testScope.runTest {
+ val lastAnyConfigurationChange by collectLastValue(underTest.onAnyConfigurationChange)
+ assertThat(lastAnyConfigurationChange).isNull()
+
+ val configurationCallback = withArgCaptor {
+ verify(configurationController).addCallback(capture())
+ }
+
+ configurationCallback.onConfigChanged(mock(Configuration::class.java))
+ runCurrent()
+ assertThat(lastAnyConfigurationChange).isNotNull()
+ }
+
+ @Test
+ fun onResolutionScale_updatesOnConfigurationChange() =
+ testScope.runTest {
+ val scaleForResolution by collectLastValue(underTest.scaleForResolution)
+ assertThat(scaleForResolution).isEqualTo(displaySizeRatio)
+
+ val configurationCallback = withArgCaptor {
+ verify(configurationController).addCallback(capture())
+ }
+
+ setPhysicalPixelDisplaySizeRatio(2f)
+ configurationCallback.onConfigChanged(mock(Configuration::class.java))
+ assertThat(scaleForResolution).isEqualTo(displaySizeRatio)
+
+ setPhysicalPixelDisplaySizeRatio(.21f)
+ configurationCallback.onConfigChanged(mock(Configuration::class.java))
+ assertThat(scaleForResolution).isEqualTo(displaySizeRatio)
+ }
+
+ @Test
+ fun onResolutionScale_nullMaxResolution() =
+ testScope.runTest {
+ val scaleForResolution by collectLastValue(underTest.scaleForResolution)
+ runCurrent()
+
+ givenNullMaxResolutionDisplayMode()
+ val configurationCallback = withArgCaptor {
+ verify(configurationController).addCallback(capture())
+ }
+ configurationCallback.onConfigChanged(mock(Configuration::class.java))
+ assertThat(scaleForResolution).isEqualTo(1f)
+ }
+
+ @Test
+ fun getResolutionScale_nullMaxResolutionDisplayMode() {
+ givenNullMaxResolutionDisplayMode()
+ assertThat(underTest.getResolutionScale()).isEqualTo(1f)
+ }
+
+ @Test
+ fun getResolutionScale_infiniteDisplayRatios() {
+ setPhysicalPixelDisplaySizeRatio(Float.POSITIVE_INFINITY)
+ assertThat(underTest.getResolutionScale()).isEqualTo(1f)
+ }
+
+ @Test
+ fun getResolutionScale_differentDisplayRatios() {
+ setPhysicalPixelDisplaySizeRatio(.5f)
+ assertThat(underTest.getResolutionScale()).isEqualTo(displaySizeRatio)
+
+ setPhysicalPixelDisplaySizeRatio(.283f)
+ assertThat(underTest.getResolutionScale()).isEqualTo(displaySizeRatio)
+
+ setPhysicalPixelDisplaySizeRatio(3.58f)
+ assertThat(underTest.getResolutionScale()).isEqualTo(displaySizeRatio)
+
+ setPhysicalPixelDisplaySizeRatio(0f)
+ assertThat(underTest.getResolutionScale()).isEqualTo(displaySizeRatio)
+
+ setPhysicalPixelDisplaySizeRatio(1f)
+ assertThat(underTest.getResolutionScale()).isEqualTo(displaySizeRatio)
+ }
+
+ private fun givenNullMaxResolutionDisplayMode() {
+ whenever(displayUtils.getMaximumResolutionDisplayMode(any())).thenReturn(null)
+ }
+
+ private fun setPhysicalPixelDisplaySizeRatio(ratio: Float) {
+ displaySizeRatio = ratio
+ whenever(displayUtils.getMaximumResolutionDisplayMode(any()))
+ .thenReturn(Display.Mode(0, 0, 0, 90f))
+ whenever(
+ displayUtils.getPhysicalPixelDisplaySizeRatio(
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ anyInt()
+ )
+ )
+ .thenReturn(ratio)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
new file mode 100644
index 000000000000..b2a1668df7aa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.common.ui.data.repository
+
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.receiveAsFlow
+
+class FakeConfigurationRepository : ConfigurationRepository {
+ private val onAnyConfigurationChangeChannel = Channel<Unit>()
+ override val onAnyConfigurationChange: Flow<Unit> =
+ onAnyConfigurationChangeChannel.receiveAsFlow()
+
+ private val _scaleForResolution = MutableStateFlow(1f)
+ override val scaleForResolution: Flow<Float> = _scaleForResolution.asStateFlow()
+
+ suspend fun onAnyConfigurationChange() {
+ onAnyConfigurationChangeChannel.send(Unit)
+ }
+
+ fun setScaleForResolution(scale: Float) {
+ _scaleForResolution.value = scale
+ }
+
+ override fun getResolutionScale(): Float {
+ return _scaleForResolution.value
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
index ef1061faeed9..07cb5d88a515 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
@@ -42,6 +42,8 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import kotlinx.coroutines.CoroutineScope;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class AssistantAttentionConditionTest extends SysuiTestCase {
@@ -51,6 +53,8 @@ public class AssistantAttentionConditionTest extends SysuiTestCase {
AssistUtils mAssistUtils;
@Mock
DreamOverlayStateController mDreamOverlayStateController;
+ @Mock
+ CoroutineScope mScope;
private AssistantAttentionCondition mAssistantAttentionCondition;
@@ -59,7 +63,7 @@ public class AssistantAttentionConditionTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mAssistantAttentionCondition =
- new AssistantAttentionCondition(mDreamOverlayStateController, mAssistUtils);
+ new AssistantAttentionCondition(mScope, mDreamOverlayStateController, mAssistUtils);
// Adding a callback also starts the condition.
mAssistantAttentionCondition.addCallback(mCallback);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
index e1c54976d734..68c79652ac00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.DreamManager;
-import android.content.Context;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
@@ -42,13 +41,12 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import kotlinx.coroutines.CoroutineScope;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamConditionTest extends SysuiTestCase {
@Mock
- Context mContext;
-
- @Mock
Condition.Callback mCallback;
@Mock
@@ -57,6 +55,9 @@ public class DreamConditionTest extends SysuiTestCase {
@Mock
KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ CoroutineScope mScope;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -68,7 +69,8 @@ public class DreamConditionTest extends SysuiTestCase {
@Test
public void testInitialDreamingState() {
when(mDreamManager.isDreaming()).thenReturn(true);
- final DreamCondition condition = new DreamCondition(mDreamManager, mKeyguardUpdateMonitor);
+ final DreamCondition condition = new DreamCondition(mScope, mDreamManager,
+ mKeyguardUpdateMonitor);
condition.addCallback(mCallback);
verify(mCallback).onConditionChanged(eq(condition));
@@ -81,7 +83,8 @@ public class DreamConditionTest extends SysuiTestCase {
@Test
public void testInitialNonDreamingState() {
when(mDreamManager.isDreaming()).thenReturn(false);
- final DreamCondition condition = new DreamCondition(mDreamManager, mKeyguardUpdateMonitor);
+ final DreamCondition condition = new DreamCondition(mScope, mDreamManager,
+ mKeyguardUpdateMonitor);
condition.addCallback(mCallback);
verify(mCallback, never()).onConditionChanged(eq(condition));
@@ -96,7 +99,8 @@ public class DreamConditionTest extends SysuiTestCase {
final ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCaptor =
ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
when(mDreamManager.isDreaming()).thenReturn(true);
- final DreamCondition condition = new DreamCondition(mDreamManager, mKeyguardUpdateMonitor);
+ final DreamCondition condition = new DreamCondition(mScope, mDreamManager,
+ mKeyguardUpdateMonitor);
condition.addCallback(mCallback);
verify(mKeyguardUpdateMonitor).registerCallback(callbackCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
index 19135d0cc800..e8cbdf3db327 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
@@ -21,7 +21,7 @@ import com.android.systemui.CoreStartable
import com.android.systemui.Dumpable
import com.android.systemui.ProtoDumpable
import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.log.LogBuffer
import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
index 0c5a74cd39fa..02555cfa783a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
@@ -19,7 +19,7 @@ package com.android.systemui.dump
import androidx.test.filters.SmallTest
import com.android.systemui.Dumpable
import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.log.LogBuffer
import com.android.systemui.util.mockito.any
import java.io.PrintWriter
import org.junit.Before
@@ -60,16 +60,14 @@ class DumpManagerTest : SysuiTestCase() {
// WHEN a dumpable is dumped explicitly
val args = arrayOf<String>()
- dumpManager.dumpTarget("dumpable2", pw, arrayOf(), tailLength = 0)
+ dumpManager.dumpTarget("dumpable2", pw, args, tailLength = 0)
// THEN only the requested one has their dump() method called
- verify(dumpable1, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
+ verify(dumpable1, never()).dump(any(), any())
verify(dumpable2).dump(pw, args)
- verify(dumpable3, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
- verify(buffer1, never()).dump(any(PrintWriter::class.java), anyInt())
- verify(buffer2, never()).dump(any(PrintWriter::class.java), anyInt())
+ verify(dumpable3, never()).dump(any(), any())
+ verify(buffer1, never()).dump(any(), anyInt())
+ verify(buffer2, never()).dump(any(), anyInt())
}
@Test
@@ -82,17 +80,15 @@ class DumpManagerTest : SysuiTestCase() {
dumpManager.registerBuffer("buffer2", buffer2)
// WHEN a buffer is dumped explicitly
- dumpManager.dumpTarget("buffer1", pw, arrayOf(), tailLength = 14)
+ val args = arrayOf<String>()
+ dumpManager.dumpTarget("buffer1", pw, args, tailLength = 14)
// THEN only the requested one has their dump() method called
- verify(dumpable1, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
- verify(dumpable2, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
- verify(dumpable2, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
+ verify(dumpable1, never()).dump(any(), any())
+ verify(dumpable2, never()).dump(any(), any())
+ verify(dumpable3, never()).dump(any(), any())
verify(buffer1).dump(pw, tailLength = 14)
- verify(buffer2, never()).dump(any(PrintWriter::class.java), anyInt())
+ verify(buffer2, never()).dump(any(), anyInt())
}
@Test
@@ -109,6 +105,122 @@ class DumpManagerTest : SysuiTestCase() {
}
@Test
+ fun testDumpTarget_selectsShortestNamedDumpable() {
+ // GIVEN a variety of registered dumpables and buffers
+ dumpManager.registerCriticalDumpable("first-dumpable", dumpable1)
+ dumpManager.registerCriticalDumpable("scnd-dumpable", dumpable2)
+ dumpManager.registerCriticalDumpable("third-dumpable", dumpable3)
+
+ // WHEN a dumpable is dumped by a suffix that matches multiple options
+ val args = arrayOf<String>()
+ dumpManager.dumpTarget("dumpable", pw, args, tailLength = 0)
+
+ // THEN the matching dumpable with the shorter name is dumped
+ verify(dumpable1, never()).dump(any(), any())
+ verify(dumpable2).dump(pw, args)
+ verify(dumpable3, never()).dump(any(), any())
+ }
+
+ @Test
+ fun testDumpTarget_selectsShortestNamedBuffer() {
+ // GIVEN a variety of registered dumpables and buffers
+ dumpManager.registerBuffer("first-buffer", buffer1)
+ dumpManager.registerBuffer("scnd-buffer", buffer2)
+
+ // WHEN a dumpable is dumped by a suffix that matches multiple options
+ val args = arrayOf<String>()
+ dumpManager.dumpTarget("buffer", pw, args, tailLength = 14)
+
+ // THEN the matching buffer with the shorter name is dumped
+ verify(buffer1, never()).dump(any(), anyInt())
+ verify(buffer2).dump(pw, tailLength = 14)
+ }
+
+ @Test
+ fun testDumpTarget_selectsShortestNamedMatch_dumpable() {
+ // GIVEN a variety of registered dumpables and buffers
+ dumpManager.registerCriticalDumpable("dumpable1", dumpable1)
+ dumpManager.registerCriticalDumpable("dumpable2", dumpable2)
+ dumpManager.registerCriticalDumpable("dumpable3", dumpable3)
+ dumpManager.registerBuffer("big-buffer1", buffer1)
+ dumpManager.registerBuffer("big-buffer2", buffer2)
+
+ // WHEN a dumpable is dumped by a suffix that matches multiple options
+ val args = arrayOf<String>()
+ dumpManager.dumpTarget("2", pw, args, tailLength = 14)
+
+ // THEN the matching dumpable with the shorter name is dumped
+ verify(dumpable1, never()).dump(any(), any())
+ verify(dumpable2).dump(pw, args)
+ verify(dumpable3, never()).dump(any(), any())
+ verify(buffer1, never()).dump(any(), anyInt())
+ verify(buffer2, never()).dump(any(), anyInt())
+ }
+
+ @Test
+ fun testDumpTarget_selectsShortestNamedMatch_buffer() {
+ // GIVEN a variety of registered dumpables and buffers
+ dumpManager.registerCriticalDumpable("dumpable1", dumpable1)
+ dumpManager.registerCriticalDumpable("dumpable2", dumpable2)
+ dumpManager.registerCriticalDumpable("dumpable3", dumpable3)
+ dumpManager.registerBuffer("buffer1", buffer1)
+ dumpManager.registerBuffer("buffer2", buffer2)
+
+ // WHEN a dumpable is dumped by a suffix that matches multiple options
+ val args = arrayOf<String>()
+ dumpManager.dumpTarget("2", pw, args, tailLength = 14)
+
+ // THEN the matching buffer with the shorter name is dumped
+ verify(dumpable1, never()).dump(any(), any())
+ verify(dumpable2, never()).dump(any(), any())
+ verify(dumpable3, never()).dump(any(), any())
+ verify(buffer1, never()).dump(any(), anyInt())
+ verify(buffer2).dump(pw, tailLength = 14)
+ }
+
+ @Test
+ fun testDumpTarget_selectsTheAlphabeticallyFirstShortestMatch_dumpable() {
+ // GIVEN a variety of registered dumpables and buffers
+ dumpManager.registerCriticalDumpable("d1x", dumpable1)
+ dumpManager.registerCriticalDumpable("d2x", dumpable2)
+ dumpManager.registerCriticalDumpable("a3x", dumpable3)
+ dumpManager.registerBuffer("ab1x", buffer1)
+ dumpManager.registerBuffer("b2x", buffer2)
+
+ // WHEN a dumpable is dumped by a suffix that matches multiple options
+ val args = arrayOf<String>()
+ dumpManager.dumpTarget("x", pw, args, tailLength = 14)
+
+ // THEN the alphabetically first dumpable/buffer (of the 3 letter names) is dumped
+ verify(dumpable1, never()).dump(any(), any())
+ verify(dumpable2, never()).dump(any(), any())
+ verify(dumpable3).dump(pw, args)
+ verify(buffer1, never()).dump(any(), anyInt())
+ verify(buffer2, never()).dump(any(), anyInt())
+ }
+
+ @Test
+ fun testDumpTarget_selectsTheAlphabeticallyFirstShortestMatch_buffer() {
+ // GIVEN a variety of registered dumpables and buffers
+ dumpManager.registerCriticalDumpable("d1x", dumpable1)
+ dumpManager.registerCriticalDumpable("d2x", dumpable2)
+ dumpManager.registerCriticalDumpable("az1x", dumpable3)
+ dumpManager.registerBuffer("b1x", buffer1)
+ dumpManager.registerBuffer("b2x", buffer2)
+
+ // WHEN a dumpable is dumped by a suffix that matches multiple options
+ val args = arrayOf<String>()
+ dumpManager.dumpTarget("x", pw, args, tailLength = 14)
+
+ // THEN the alphabetically first dumpable/buffer (of the 3 letter names) is dumped
+ verify(dumpable1, never()).dump(any(), any())
+ verify(dumpable2, never()).dump(any(), any())
+ verify(dumpable3, never()).dump(any(), any())
+ verify(buffer1).dump(pw, tailLength = 14)
+ verify(buffer2, never()).dump(any(), anyInt())
+ }
+
+ @Test
fun testDumpDumpables() {
// GIVEN a variety of registered dumpables and buffers
dumpManager.registerCriticalDumpable("dumpable1", dumpable1)
@@ -125,8 +237,8 @@ class DumpManagerTest : SysuiTestCase() {
verify(dumpable1).dump(pw, args)
verify(dumpable2).dump(pw, args)
verify(dumpable3).dump(pw, args)
- verify(buffer1, never()).dump(any(PrintWriter::class.java), anyInt())
- verify(buffer2, never()).dump(any(PrintWriter::class.java), anyInt())
+ verify(buffer1, never()).dump(any(), anyInt())
+ verify(buffer2, never()).dump(any(), anyInt())
}
@Test
@@ -142,12 +254,9 @@ class DumpManagerTest : SysuiTestCase() {
dumpManager.dumpBuffers(pw, tailLength = 1)
// THEN all buffers are dumped (and no dumpables)
- verify(dumpable1, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
- verify(dumpable2, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
- verify(dumpable3, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
+ verify(dumpable1, never()).dump(any(), any())
+ verify(dumpable2, never()).dump(any(), any())
+ verify(dumpable3, never()).dump(any(), any())
verify(buffer1).dump(pw, tailLength = 1)
verify(buffer2).dump(pw, tailLength = 1)
}
@@ -168,10 +277,9 @@ class DumpManagerTest : SysuiTestCase() {
// THEN only critical modules are dumped (and no buffers)
verify(dumpable1).dump(pw, args)
verify(dumpable2).dump(pw, args)
- verify(dumpable3, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
- verify(buffer1, never()).dump(any(PrintWriter::class.java), anyInt())
- verify(buffer2, never()).dump(any(PrintWriter::class.java), anyInt())
+ verify(dumpable3, never()).dump(any(), any())
+ verify(buffer1, never()).dump(any(), anyInt())
+ verify(buffer2, never()).dump(any(), anyInt())
}
@Test
@@ -188,10 +296,8 @@ class DumpManagerTest : SysuiTestCase() {
dumpManager.dumpNormal(pw, args, tailLength = 2)
// THEN the normal module and all buffers are dumped
- verify(dumpable1, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
- verify(dumpable2, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
+ verify(dumpable1, never()).dump(any(), any())
+ verify(dumpable2, never()).dump(any(), any())
verify(dumpable3).dump(pw, args)
verify(buffer1).dump(pw, tailLength = 2)
verify(buffer2).dump(pw, tailLength = 2)
@@ -213,9 +319,7 @@ class DumpManagerTest : SysuiTestCase() {
// THEN the unregistered dumpables (both normal and critical) are not dumped
verify(dumpable1).dump(pw, args)
- verify(dumpable2, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
- verify(dumpable3, never())
- .dump(any(PrintWriter::class.java), any(Array<String>::class.java))
+ verify(dumpable2, never()).dump(any(), any())
+ verify(dumpable3, never()).dump(any(), any())
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
index 64547f4463d1..bd029a727ee3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
@@ -16,9 +16,9 @@
package com.android.systemui.dump
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogcatEchoTracker
/**
* Creates a LogBuffer that will echo everything to logcat, which is useful for debugging tests.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 1d0b58a8e0f4..d73c2c76272e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -54,6 +54,7 @@ import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.shared.model.WakeSleepReason
import com.android.systemui.keyguard.shared.model.WakefulnessModel
@@ -234,6 +235,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
faceDetectBuffer,
faceAuthBuffer,
keyguardTransitionInteractor,
+ featureFlags,
dumpManager,
)
}
@@ -612,6 +614,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
authStatus()
detectStatus()
authRunning()
+ bypassEnabled()
lockedOut()
canFaceAuthRun()
authenticated()
@@ -847,7 +850,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
fun schedulesFaceManagerWatchdogWhenKeyguardIsGoneFromDozing() =
testScope.runTest {
keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.DOZING, to = KeyguardState.GONE)
+ TransitionStep(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.FINISHED
+ )
)
runCurrent()
@@ -858,7 +865,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
fun schedulesFaceManagerWatchdogWhenKeyguardIsGoneFromAod() =
testScope.runTest {
keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.AOD, to = KeyguardState.GONE)
+ TransitionStep(
+ from = KeyguardState.AOD,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.FINISHED
+ )
)
runCurrent()
@@ -869,7 +880,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
fun schedulesFaceManagerWatchdogWhenKeyguardIsGoneFromLockscreen() =
testScope.runTest {
keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.FINISHED
+ )
)
runCurrent()
@@ -880,7 +895,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
fun schedulesFaceManagerWatchdogWhenKeyguardIsGoneFromBouncer() =
testScope.runTest {
keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.PRIMARY_BOUNCER, to = KeyguardState.GONE)
+ TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.FINISHED
+ )
)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index d0bfaa9bedc9..5afc4059357c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -23,8 +23,8 @@ import android.util.Log.TerribleFailureHandler
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators
import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.Interpolators
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
index bf3c73a2c94e..c2195c7bc2c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
@@ -24,8 +24,8 @@ import com.android.keyguard.logging.TrustRepositoryLogger
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.user.data.repository.FakeUserRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
new file mode 100644
index 000000000000..069a4862ccdc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.doze.util.BurnInHelperWrapper
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertEquals
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BurnInInteractorTest : SysuiTestCase() {
+ private val burnInOffset = 7
+ private var burnInProgress = 0f
+
+ @Mock private lateinit var burnInHelperWrapper: BurnInHelperWrapper
+
+ private lateinit var configurationRepository: FakeConfigurationRepository
+ private lateinit var systemClock: FakeSystemClock
+ private lateinit var testScope: TestScope
+ private lateinit var underTest: BurnInInteractor
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ configurationRepository = FakeConfigurationRepository()
+ systemClock = FakeSystemClock()
+
+ whenever(burnInHelperWrapper.burnInOffset(anyInt(), anyBoolean())).thenReturn(burnInOffset)
+ setBurnInProgress(.65f)
+
+ testScope = TestScope()
+ underTest =
+ BurnInInteractor(
+ context,
+ burnInHelperWrapper,
+ testScope.backgroundScope,
+ configurationRepository,
+ systemClock,
+ )
+ }
+
+ @Test
+ fun dozeTimeTick_updatesOnDozeTimeTick() =
+ testScope.runTest {
+ // Initial state set to 0
+ val lastDozeTimeTick by collectLastValue(underTest.dozeTimeTick)
+ assertEquals(0L, lastDozeTimeTick)
+
+ // WHEN dozeTimeTick updated
+ incrementUptimeMillis()
+ underTest.dozeTimeTick()
+
+ // THEN listeners were updated to the latest uptime millis
+ assertThat(systemClock.uptimeMillis()).isEqualTo(lastDozeTimeTick)
+ }
+
+ @Test
+ fun udfpsBurnInOffset_updatesOnResolutionScaleChange() =
+ testScope.runTest {
+ val udfpsBurnInOffsetX by collectLastValue(underTest.udfpsBurnInXOffset)
+ val udfpsBurnInOffsetY by collectLastValue(underTest.udfpsBurnInYOffset)
+ assertThat(udfpsBurnInOffsetX).isEqualTo(burnInOffset)
+ assertThat(udfpsBurnInOffsetY).isEqualTo(burnInOffset)
+
+ configurationRepository.setScaleForResolution(3f)
+ assertThat(udfpsBurnInOffsetX).isEqualTo(burnInOffset * 3)
+ assertThat(udfpsBurnInOffsetY).isEqualTo(burnInOffset * 3)
+
+ configurationRepository.setScaleForResolution(.5f)
+ assertThat(udfpsBurnInOffsetX).isEqualTo(burnInOffset / 2)
+ assertThat(udfpsBurnInOffsetY).isEqualTo(burnInOffset / 2)
+ }
+
+ @Test
+ fun udfpsBurnInProgress_updatesOnDozeTimeTick() =
+ testScope.runTest {
+ val udfpsBurnInProgress by collectLastValue(underTest.udfpsBurnInProgress)
+ assertThat(udfpsBurnInProgress).isEqualTo(burnInProgress)
+
+ setBurnInProgress(.88f)
+ incrementUptimeMillis()
+ underTest.dozeTimeTick()
+ assertThat(udfpsBurnInProgress).isEqualTo(burnInProgress)
+
+ setBurnInProgress(.92f)
+ incrementUptimeMillis()
+ underTest.dozeTimeTick()
+ assertThat(udfpsBurnInProgress).isEqualTo(burnInProgress)
+
+ setBurnInProgress(.32f)
+ incrementUptimeMillis()
+ underTest.dozeTimeTick()
+ assertThat(udfpsBurnInProgress).isEqualTo(burnInProgress)
+ }
+
+ private fun incrementUptimeMillis() {
+ systemClock.setUptimeMillis(systemClock.uptimeMillis() + 5)
+ }
+
+ private fun setBurnInProgress(progress: Float) {
+ burnInProgress = progress
+ whenever(burnInHelperWrapper.burnInProgressOffset()).thenReturn(burnInProgress)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
index a5b78b74fcdf..3efe38295f3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.keyguard.ui
import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
diff --git a/packages/SystemUI/plugin/tests/log/LogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
index a39b856f0f49..0cf6d3da7e9c 100644
--- a/packages/SystemUI/plugin/tests/log/LogBufferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
@@ -2,7 +2,6 @@ package com.android.systemui.log
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.log.LogBuffer
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
index a003e1d9d1f3..43e430fd7fa2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
@@ -19,7 +19,9 @@ package com.android.systemui.log.table
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
+import com.android.systemui.log.table.TableChange.Companion.MAX_STRING_LENGTH
import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertTrue
import org.junit.Test
@SmallTest
@@ -326,4 +328,152 @@ class TableChangeTest : SysuiTestCase() {
assertThat(underTest.getVal()).doesNotContain(IS_INITIAL_PREFIX)
}
+
+ @Test
+ fun constructor_columnAndValueTooLong_truncated() {
+ val underTest =
+ TableChange(
+ columnPrefix = "P".repeat(MAX_STRING_LENGTH + 10),
+ columnName = "N".repeat(MAX_STRING_LENGTH + 10),
+ type = TableChange.DataType.STRING,
+ str = "V".repeat(MAX_STRING_LENGTH + 10),
+ )
+
+ assertThat(underTest.getName()).contains("P".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("P".repeat(MAX_STRING_LENGTH + 1))
+ assertThat(underTest.getName()).contains("N".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("N".repeat(MAX_STRING_LENGTH + 1))
+ assertThat(underTest.getVal()).isEqualTo("V".repeat(MAX_STRING_LENGTH))
+ }
+
+ @Test
+ fun constructor_columnNameNotTooLong_noReallocation() {
+ val inputColumnName = "fakeName"
+ val inputValue = "fakeValue"
+ val underTest =
+ TableChange(
+ columnPrefix = "",
+ columnName = inputColumnName,
+ type = TableChange.DataType.STRING,
+ str = inputValue,
+ )
+
+ // Use referential equality to verify we didn't reallocate a new string when the string is
+ // *not* too long.
+ assertTrue(underTest.getColumnName() === inputColumnName)
+ }
+
+ @Test
+ fun reset_columnPrefixTooLong_truncated() {
+ val underTest = TableChange()
+
+ underTest.reset(
+ timestamp = 1L,
+ columnPrefix = "P".repeat(MAX_STRING_LENGTH + 10),
+ columnName = "name",
+ isInitial = false,
+ )
+
+ assertThat(underTest.getName()).contains("P".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("P".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun reset_columnNameTooLong_truncated() {
+ val underTest = TableChange()
+
+ underTest.reset(
+ timestamp = 1L,
+ columnPrefix = "prefix",
+ columnName = "N".repeat(MAX_STRING_LENGTH + 10),
+ isInitial = false,
+ )
+
+ assertThat(underTest.getName()).contains("N".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("N".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun reset_columnNameNotTooLong_noReallocation() {
+ val underTest = TableChange()
+ val shortColumnName = "shortColumnName"
+
+ underTest.reset(
+ timestamp = 1L,
+ columnPrefix = "prefix",
+ columnName = shortColumnName,
+ isInitial = false,
+ )
+
+ // Use referential equality to verify we didn't reallocate a new string when the string is
+ // *not* too long.
+ assertTrue(underTest.getColumnName() === shortColumnName)
+ }
+
+ @Test
+ fun setString_valueTooLong_truncated() {
+ val underTest = TableChange()
+
+ underTest.set("V".repeat(MAX_STRING_LENGTH + 1))
+
+ assertThat(underTest.getVal()).isEqualTo("V".repeat(MAX_STRING_LENGTH))
+ }
+
+ @Test
+ fun updateTo_newColumnPrefixTooLong_truncated() {
+ val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+ underTest.set(42)
+
+ val new =
+ TableChange(
+ columnPrefix = "P".repeat(MAX_STRING_LENGTH + 10),
+ columnName = "name",
+ )
+ underTest.updateTo(new)
+
+ assertThat(underTest.getName()).contains("P".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("P".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun updateTo_newColumnNameTooLong_truncated() {
+ val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+ underTest.set(42)
+
+ val new =
+ TableChange(
+ columnPrefix = "prefix",
+ columnName = "N".repeat(MAX_STRING_LENGTH + 10),
+ )
+ underTest.updateTo(new)
+
+ assertThat(underTest.getName()).contains("N".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("N".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun updateTo_columnNameNotTooLong_noReallocation() {
+ val underTest = TableChange()
+ val shortColumnName = "shortColumnName"
+ val new = TableChange(columnPrefix = "prefix", columnName = shortColumnName)
+
+ underTest.updateTo(new)
+
+ // Use referential equality to verify we didn't reallocate a new string when the string is
+ // *not* too long.
+ assertTrue(underTest.getColumnName() === shortColumnName)
+ }
+
+ @Test
+ fun updateTo_newValTooLong_truncated() {
+ val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+ underTest.set("value")
+
+ val new = TableChange()
+ new.set("V".repeat(MAX_STRING_LENGTH + 10))
+
+ underTest.updateTo(new)
+
+ assertThat(underTest.getVal()).isEqualTo("V".repeat(MAX_STRING_LENGTH))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
index a2b2322899b7..12f46898ab8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
@@ -18,9 +18,10 @@ package com.android.systemui.log.table
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.table.TableChange.Companion.MAX_STRING_LENGTH
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
@@ -576,6 +577,112 @@ class TableLogBufferTest : SysuiTestCase() {
}
@Test
+ fun dumpChanges_tooLongColumnPrefix_viaLogChange_truncated() {
+ underTest.logChange(
+ prefix = "P".repeat(MAX_STRING_LENGTH + 10),
+ columnName = "name",
+ value = true,
+ )
+
+ val dumpedString = dumpChanges()
+
+ assertThat(dumpedString).contains("P".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("P".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun dumpChanges_tooLongColumnPrefix_viaLogDiffs_truncated() {
+ val prevDiffable = object : TestDiffable() {}
+ val nextDiffable =
+ object : TestDiffable() {
+ override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+ row.logChange("status", "value")
+ }
+ }
+
+ // WHEN the column prefix is too large
+ underTest.logDiffs(
+ columnPrefix = "P".repeat(MAX_STRING_LENGTH + 10),
+ prevDiffable,
+ nextDiffable,
+ )
+
+ val dumpedString = dumpChanges()
+
+ // THEN it's truncated to the max length
+ assertThat(dumpedString).contains("P".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("P".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun dumpChanges_tooLongColumnName_viaLogChange_truncated() {
+ underTest.logChange(
+ prefix = "prefix",
+ columnName = "N".repeat(MAX_STRING_LENGTH + 10),
+ value = 10,
+ )
+
+ val dumpedString = dumpChanges()
+
+ assertThat(dumpedString).contains("N".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("N".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun dumpChanges_tooLongColumnName_viaLogDiffs_truncated() {
+ val prevDiffable = object : TestDiffable() {}
+ val nextDiffable =
+ object : TestDiffable() {
+ override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+ // WHEN the column name is too large
+ row.logChange(columnName = "N".repeat(MAX_STRING_LENGTH + 10), "value")
+ }
+ }
+
+ underTest.logDiffs(columnPrefix = "prefix", prevDiffable, nextDiffable)
+
+ val dumpedString = dumpChanges()
+
+ // THEN it's truncated to the max length
+ assertThat(dumpedString).contains("N".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("N".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun dumpChanges_tooLongValue_viaLogChange_truncated() {
+ underTest.logChange(
+ prefix = "prefix",
+ columnName = "name",
+ value = "V".repeat(MAX_STRING_LENGTH + 10),
+ )
+
+ val dumpedString = dumpChanges()
+
+ assertThat(dumpedString).contains("V".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("V".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun dumpChanges_tooLongValue_viaLogDiffs_truncated() {
+ val prevDiffable = object : TestDiffable() {}
+ val nextDiffable =
+ object : TestDiffable() {
+ override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+ // WHEN the value is too large
+ row.logChange("columnName", value = "V".repeat(MAX_STRING_LENGTH + 10))
+ }
+ }
+
+ underTest.logDiffs(columnPrefix = "prefix", prevDiffable, nextDiffable)
+
+ val dumpedString = dumpChanges()
+
+ // THEN it's truncated to the max length
+ assertThat(dumpedString).contains("V".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("V".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
fun dumpChanges_rotatesIfBufferIsFull() {
lateinit var valToDump: String
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
index 8da1c646109d..b322bb7d6b46 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
@@ -19,9 +19,9 @@ package com.android.systemui.media.taptotransfer.common
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogcatEchoTracker
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
index 95df484cddc2..64f3fd304ca6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
@@ -19,9 +19,9 @@ package com.android.systemui.media.taptotransfer.receiver
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogcatEchoTracker
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
index 003375709a16..2287da572795 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
@@ -19,9 +19,9 @@ package com.android.systemui.media.taptotransfer.sender
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogcatEchoTracker
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
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 c17d6d192698..452658004733 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
@@ -296,8 +296,8 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
assertThat(underTest.getPickerScreenState())
.isEqualTo(
KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
- listOf("Select a default notes app to use notetaking shortcut"),
- actionText = "Open settings",
+ listOf("Select a default notes app to use the notetaking shortcut"),
+ actionText = "Select app",
actionComponentName =
"${context.packageName}$COMPONENT_NAME_SEPARATOR" +
"$ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java
index fb7197706ddc..ff60fcda53e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java
@@ -37,6 +37,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import kotlinx.coroutines.CoroutineScope;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
@@ -47,6 +49,9 @@ public class SystemProcessConditionTest extends SysuiTestCase {
@Mock
Monitor.Callback mCallback;
+ @Mock
+ CoroutineScope mScope;
+
private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
@Before
@@ -61,7 +66,7 @@ public class SystemProcessConditionTest extends SysuiTestCase {
@Test
public void testConditionFailsWithNonSystemProcess() {
- final Condition condition = new SystemProcessCondition(mProcessWrapper);
+ final Condition condition = new SystemProcessCondition(mScope, mProcessWrapper);
when(mProcessWrapper.isSystemUser()).thenReturn(false);
final Monitor monitor = new Monitor(mExecutor);
@@ -82,7 +87,7 @@ public class SystemProcessConditionTest extends SysuiTestCase {
@Test
public void testConditionSucceedsWithSystemProcess() {
- final Condition condition = new SystemProcessCondition(mProcessWrapper);
+ final Condition condition = new SystemProcessCondition(mScope, mProcessWrapper);
when(mProcessWrapper.isSystemUser()).thenReturn(true);
final Monitor monitor = new Monitor(mExecutor);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
index 68c10f20f6f7..aacc695ef301 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
@@ -20,7 +20,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
index e106741499ab..41545fc2abfd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
@@ -30,6 +30,7 @@ import android.os.Handler;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.testing.TestableResources;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
@@ -94,14 +95,18 @@ public class RotationLockTileTest extends SysuiTestCase {
private RotationLockController mController;
private TestableLooper mTestableLooper;
private RotationLockTile mLockTile;
+ private TestableResources mTestableResources;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
+ mTestableResources = mContext.getOrCreateTestableResources();
when(mHost.getContext()).thenReturn(mContext);
when(mHost.getUserContext()).thenReturn(mContext);
+ mTestableResources.addOverride(com.android.internal.R.bool.config_allowRotationResolver,
+ true);
mController = new RotationLockControllerImpl(mRotationPolicyWrapper,
mDeviceStateRotationLockSettingController, DEFAULT_SETTINGS);
@@ -208,6 +213,32 @@ public class RotationLockTileTest extends SysuiTestCase {
}
@Test
+ public void testSecondaryString_rotationResolverDisabled_isEmpty() {
+ mTestableResources.addOverride(com.android.internal.R.bool.config_allowRotationResolver,
+ false);
+ mLockTile = new RotationLockTile(
+ mHost,
+ mUiEventLogger,
+ mTestableLooper.getLooper(),
+ new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
+ mMetricsLogger,
+ mStatusBarStateController,
+ mActivityStarter,
+ mQSLogger,
+ mController,
+ mPrivacyManager,
+ mBatteryController,
+ new FakeSettings()
+ );
+
+ mLockTile.refreshState();
+ mTestableLooper.processAllMessages();
+
+ assertEquals("", mLockTile.getState().secondaryLabel.toString());
+ }
+
+ @Test
public void testIcon_whenDisabled_isOffState() {
QSTile.BooleanState state = new QSTile.BooleanState();
disableAutoRotation();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index a1d78cbba7f9..7c30843bb70b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -18,7 +18,6 @@ package com.android.systemui.screenrecord;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -94,6 +93,7 @@ public class RecordingServiceTest extends SysuiTestCase {
doReturn(mContext.getUserId()).when(mRecordingService).getUserId();
doReturn(mContext.getPackageName()).when(mRecordingService).getPackageName();
doReturn(mContext.getContentResolver()).when(mRecordingService).getContentResolver();
+ doReturn(mContext.getResources()).when(mRecordingService).getResources();
// Mock notifications
doNothing().when(mRecordingService).createRecordingNotification();
@@ -101,7 +101,7 @@ public class RecordingServiceTest extends SysuiTestCase {
doReturn(mNotification).when(mRecordingService).createSaveNotification(any());
doNothing().when(mRecordingService).createErrorNotification();
doNothing().when(mRecordingService).showErrorToast(anyInt());
- doNothing().when(mRecordingService).stopForeground(anyBoolean());
+ doNothing().when(mRecordingService).stopForeground(anyInt());
doNothing().when(mRecordingService).startForeground(anyInt(), any());
doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
index 31a33d4ff908..cbd9dba3cdbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
@@ -30,6 +30,7 @@ import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivit
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -127,6 +128,9 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase {
@Before
public void setUp() {
+ assumeFalse("Skip test: does not apply to watches",
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
+
MockitoAnnotations.initMocks(this);
mMainHandler = mContext.getMainThreadHandler();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
new file mode 100644
index 000000000000..d4751c86a87f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableResources
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.fragments.FragmentService
+import com.android.systemui.navigationbar.NavigationModeController
+import com.android.systemui.recents.OverviewProxyService
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@SmallTest
+class NotificationsQSContainerControllerTest : SysuiTestCase() {
+
+ @Mock lateinit var view: NotificationsQuickSettingsContainer
+ @Mock lateinit var navigationModeController: NavigationModeController
+ @Mock lateinit var overviewProxyService: OverviewProxyService
+ @Mock lateinit var shadeHeaderController: ShadeHeaderController
+ @Mock lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
+ @Mock lateinit var fragmentService: FragmentService
+
+ lateinit var underTest: NotificationsQSContainerController
+
+ private lateinit var fakeResources: TestableResources
+
+ private val delayableExecutor: DelayableExecutor = FakeExecutor(FakeSystemClock())
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ fakeResources = TestableResources(context.resources)
+
+ whenever(view.resources).thenReturn(fakeResources.resources)
+
+ underTest =
+ NotificationsQSContainerController(
+ view,
+ navigationModeController,
+ overviewProxyService,
+ shadeHeaderController,
+ shadeExpansionStateManager,
+ fragmentService,
+ delayableExecutor,
+ )
+ }
+
+ @Test
+ fun testSmallScreen_updateResources_splitShadeHeightIsSet() {
+ with(fakeResources) {
+ addOverride(R.bool.config_use_large_screen_shade_header, false)
+ addOverride(R.dimen.qs_header_height, 1)
+ addOverride(R.dimen.large_screen_shade_header_height, 2)
+ }
+
+ underTest.updateResources()
+
+ val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
+ verify(view).applyConstraints(capture(captor))
+ assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(1)
+ }
+
+ @Test
+ fun testLargeScreen_updateResources_splitShadeHeightIsSet() {
+ with(fakeResources) {
+ addOverride(R.bool.config_use_large_screen_shade_header, true)
+ addOverride(R.dimen.qs_header_height, 1)
+ addOverride(R.dimen.large_screen_shade_header_height, 2)
+ }
+
+ underTest.updateResources()
+
+ val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
+ verify(view).applyConstraints(capture(captor))
+ assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(2)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index 9fe75abddf9c..20da8a619100 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -33,9 +33,9 @@ import android.widget.TextView
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
new file mode 100644
index 000000000000..1a0e932d7e8a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.condition
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shared.condition.Condition.START_EAGERLY
+import com.android.systemui.shared.condition.Condition.START_LAZILY
+import com.android.systemui.shared.condition.Condition.START_WHEN_NEEDED
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class CombinedConditionTest : SysuiTestCase() {
+
+ class FakeCondition
+ constructor(
+ scope: CoroutineScope,
+ initialValue: Boolean?,
+ overriding: Boolean = false,
+ @StartStrategy private val startStrategy: Int = START_WHEN_NEEDED,
+ ) : Condition(scope, initialValue, overriding) {
+ private var _started = false
+ val started: Boolean
+ get() = _started
+
+ override fun start() {
+ _started = true
+ }
+
+ override fun stop() {
+ _started = false
+ }
+
+ override fun getStartStrategy(): Int {
+ return startStrategy
+ }
+
+ fun setValue(value: Boolean?) {
+ value?.also { updateCondition(value) } ?: clearCondition()
+ }
+ }
+
+ @Test
+ fun testOrOperatorWithMixedConditions() = runSelfCancelingTest {
+ val startWhenNeededCondition =
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_WHEN_NEEDED)
+ val eagerCondition =
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_EAGERLY)
+ val lazyCondition =
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_LAZILY)
+
+ val combinedCondition =
+ CombinedCondition(
+ scope = this,
+ conditions =
+ listOf(
+ eagerCondition,
+ lazyCondition,
+ startWhenNeededCondition,
+ ),
+ operand = Evaluator.OP_OR
+ )
+
+ val callback = Condition.Callback {}
+ combinedCondition.addCallback(callback)
+
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(lazyCondition.started).isTrue()
+ assertThat(startWhenNeededCondition.started).isTrue()
+
+ eagerCondition.setValue(true)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(lazyCondition.started).isTrue()
+ assertThat(startWhenNeededCondition.started).isFalse()
+
+ startWhenNeededCondition.setValue(true)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(lazyCondition.started).isTrue()
+ assertThat(startWhenNeededCondition.started).isFalse()
+
+ startWhenNeededCondition.setValue(false)
+ eagerCondition.setValue(false)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(lazyCondition.started).isTrue()
+ assertThat(startWhenNeededCondition.started).isTrue()
+ }
+
+ @Test
+ fun testAndOperatorWithMixedConditions() = runSelfCancelingTest {
+ val startWhenNeededCondition =
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_WHEN_NEEDED)
+ val eagerCondition =
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_EAGERLY)
+ val lazyCondition =
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_LAZILY)
+
+ val combinedCondition =
+ CombinedCondition(
+ scope = this,
+ conditions =
+ listOf(
+ startWhenNeededCondition,
+ lazyCondition,
+ eagerCondition,
+ ),
+ operand = Evaluator.OP_AND
+ )
+
+ val callback = Condition.Callback {}
+ combinedCondition.addCallback(callback)
+
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(lazyCondition.started).isFalse()
+ assertThat(startWhenNeededCondition.started).isFalse()
+
+ eagerCondition.setValue(true)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(startWhenNeededCondition.started).isTrue()
+ assertThat(lazyCondition.started).isFalse()
+
+ startWhenNeededCondition.setValue(true)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(startWhenNeededCondition.started).isFalse()
+ assertThat(lazyCondition.started).isTrue()
+
+ startWhenNeededCondition.setValue(false)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(startWhenNeededCondition.started).isFalse()
+ assertThat(lazyCondition.started).isTrue()
+
+ startWhenNeededCondition.setValue(true)
+ lazyCondition.setValue(true)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(startWhenNeededCondition.started).isTrue()
+ assertThat(lazyCondition.started).isTrue()
+ }
+
+ @Test
+ fun testAndOperatorWithStartWhenNeededConditions() = runSelfCancelingTest {
+ val conditions =
+ 0.rangeTo(2)
+ .map {
+ FakeCondition(
+ scope = this,
+ initialValue = false,
+ startStrategy = START_WHEN_NEEDED
+ )
+ }
+ .toList()
+
+ val combinedCondition =
+ CombinedCondition(scope = this, conditions = conditions, operand = Evaluator.OP_AND)
+
+ val callback = Condition.Callback {}
+ combinedCondition.addCallback(callback)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ // Only the first condition should be started
+ assertThat(areStarted(conditions)).containsExactly(true, false, false).inOrder()
+
+ conditions[0].setValue(true)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(areStarted(conditions)).containsExactly(false, true, false).inOrder()
+
+ conditions[1].setValue(true)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(areStarted(conditions)).containsExactly(false, false, true).inOrder()
+
+ conditions[2].setValue(true)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(areStarted(conditions)).containsExactly(true, true, true).inOrder()
+
+ conditions[0].setValue(false)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(areStarted(conditions)).containsExactly(true, false, false).inOrder()
+ }
+
+ @Test
+ fun testOrOperatorWithStartWhenNeededConditions() = runSelfCancelingTest {
+ val conditions =
+ 0.rangeTo(2)
+ .map {
+ FakeCondition(
+ scope = this,
+ initialValue = false,
+ startStrategy = START_WHEN_NEEDED
+ )
+ }
+ .toList()
+
+ val combinedCondition =
+ CombinedCondition(scope = this, conditions = conditions, operand = Evaluator.OP_OR)
+
+ val callback = Condition.Callback {}
+ combinedCondition.addCallback(callback)
+ // Default is to monitor all conditions when false
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(areStarted(conditions)).containsExactly(true, true, true).inOrder()
+
+ // Condition 2 is true, so we should only monitor condition 2
+ conditions[1].setValue(true)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(areStarted(conditions)).containsExactly(false, true, false).inOrder()
+
+ // Condition 2 becomes false, so we go back to monitoring all conditions
+ conditions[1].setValue(false)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(areStarted(conditions)).containsExactly(true, true, true).inOrder()
+
+ // Condition 3 becomes true, so we only monitor condition 3
+ conditions[2].setValue(true)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(areStarted(conditions)).containsExactly(false, false, true).inOrder()
+
+ // Condition 2 becomes true, but we are still only monitoring condition 3
+ conditions[1].setValue(true)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(areStarted(conditions)).containsExactly(false, false, true).inOrder()
+
+ // Condition 3 becomes false, so we should now only be monitoring condition 2
+ conditions[2].setValue(false)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(areStarted(conditions)).containsExactly(false, true, false).inOrder()
+ }
+
+ @Test
+ fun testRemovingCallbackWillStopMonitoringAllConditions() = runSelfCancelingTest {
+ val conditions =
+ 0.rangeTo(2)
+ .map {
+ FakeCondition(
+ scope = this,
+ initialValue = false,
+ startStrategy = START_WHEN_NEEDED
+ )
+ }
+ .toList()
+
+ val combinedCondition =
+ CombinedCondition(scope = this, conditions = conditions, operand = Evaluator.OP_OR)
+
+ val callback = Condition.Callback {}
+ combinedCondition.addCallback(callback)
+ assertThat(areStarted(conditions)).containsExactly(true, true, true)
+
+ combinedCondition.removeCallback(callback)
+ assertThat(areStarted(conditions)).containsExactly(false, false, false)
+ }
+
+ @Test
+ fun testOverridingConditionSkipsOtherConditions() = runSelfCancelingTest {
+ val startWhenNeededCondition =
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_WHEN_NEEDED)
+ val eagerCondition =
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_EAGERLY)
+ val lazyCondition =
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_LAZILY)
+ val overridingCondition1 =
+ FakeCondition(scope = this, initialValue = null, overriding = true)
+ val overridingCondition2 =
+ FakeCondition(scope = this, initialValue = null, overriding = true)
+
+ val combinedCondition =
+ CombinedCondition(
+ scope = this,
+ conditions =
+ listOf(
+ eagerCondition,
+ overridingCondition1,
+ lazyCondition,
+ startWhenNeededCondition,
+ overridingCondition2
+ ),
+ operand = Evaluator.OP_OR
+ )
+
+ val callback = Condition.Callback {}
+ combinedCondition.addCallback(callback)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(lazyCondition.started).isTrue()
+ assertThat(startWhenNeededCondition.started).isTrue()
+ assertThat(overridingCondition1.started).isTrue()
+
+ // Overriding condition is true, so we should stop monitoring all other conditions
+ overridingCondition1.setValue(true)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(eagerCondition.started).isFalse()
+ assertThat(lazyCondition.started).isFalse()
+ assertThat(startWhenNeededCondition.started).isFalse()
+ assertThat(overridingCondition1.started).isTrue()
+ assertThat(overridingCondition2.started).isFalse()
+
+ // Overriding condition is false, so we should only monitor other overriding conditions
+ overridingCondition1.setValue(false)
+ eagerCondition.setValue(true)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(eagerCondition.started).isFalse()
+ assertThat(lazyCondition.started).isFalse()
+ assertThat(startWhenNeededCondition.started).isFalse()
+ assertThat(overridingCondition1.started).isTrue()
+ assertThat(overridingCondition2.started).isTrue()
+
+ // Second overriding condition is true, condition 1 is still true
+ overridingCondition2.setValue(true)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(eagerCondition.started).isFalse()
+ assertThat(lazyCondition.started).isFalse()
+ assertThat(startWhenNeededCondition.started).isFalse()
+ assertThat(overridingCondition1.started).isFalse()
+ assertThat(overridingCondition2.started).isTrue()
+
+ // Overriding condition is cleared, condition 1 is still true
+ overridingCondition1.setValue(null)
+ overridingCondition2.setValue(null)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(eagerCondition.started).isTrue()
+ assertThat(lazyCondition.started).isFalse()
+ assertThat(startWhenNeededCondition.started).isFalse()
+ assertThat(overridingCondition1.started).isTrue()
+ assertThat(overridingCondition2.started).isTrue()
+ }
+
+ @Test
+ fun testAndOperatorCorrectlyHandlesUnknownValues() = runSelfCancelingTest {
+ val conditions =
+ 0.rangeTo(2)
+ .map {
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_EAGERLY)
+ }
+ .toList()
+
+ val combinedCondition =
+ CombinedCondition(scope = this, conditions = conditions, operand = Evaluator.OP_AND)
+
+ val callback = Condition.Callback {}
+ combinedCondition.addCallback(callback)
+
+ conditions[0].setValue(null)
+ conditions[1].setValue(true)
+ conditions[2].setValue(false)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(combinedCondition.isConditionSet).isTrue()
+
+ // The condition should not be set since the value is unknown
+ conditions[2].setValue(true)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(combinedCondition.isConditionSet).isFalse()
+
+ conditions[0].setValue(true)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(combinedCondition.isConditionSet).isTrue()
+ }
+
+ @Test
+ fun testOrOperatorCorrectlyHandlesUnknownValues() = runSelfCancelingTest {
+ val conditions =
+ 0.rangeTo(2)
+ .map {
+ FakeCondition(scope = this, initialValue = false, startStrategy = START_EAGERLY)
+ }
+ .toList()
+
+ val combinedCondition =
+ CombinedCondition(scope = this, conditions = conditions, operand = Evaluator.OP_OR)
+
+ val callback = Condition.Callback {}
+ combinedCondition.addCallback(callback)
+
+ conditions[0].setValue(null)
+ conditions[1].setValue(true)
+ conditions[2].setValue(false)
+ assertThat(combinedCondition.isConditionMet).isTrue()
+ assertThat(combinedCondition.isConditionSet).isTrue()
+
+ conditions[1].setValue(false)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ // The condition should not be set since the value is unknown
+ assertThat(combinedCondition.isConditionSet).isFalse()
+ }
+
+ @Test
+ fun testEmptyConditions() = runSelfCancelingTest {
+ for (operand in intArrayOf(Evaluator.OP_OR, Evaluator.OP_AND)) {
+ val combinedCondition =
+ CombinedCondition(
+ scope = this,
+ conditions = emptyList(),
+ operand = operand,
+ )
+
+ val callback = Condition.Callback {}
+ combinedCondition.addCallback(callback)
+ assertThat(combinedCondition.isConditionMet).isFalse()
+ assertThat(combinedCondition.isConditionSet).isFalse()
+ }
+ }
+
+ private fun areStarted(conditions: List<FakeCondition>): List<Boolean> {
+ return conditions.map { it.started }
+ }
+
+ /**
+ * Executes the given block of execution within the scope of a dedicated [CoroutineScope] which
+ * is then automatically canceled and cleaned-up.
+ */
+ private fun runSelfCancelingTest(
+ block: suspend CoroutineScope.() -> Unit,
+ ) =
+ runBlocking(IMMEDIATE) {
+ val scope = CoroutineScope(coroutineContext + Job())
+ block(scope)
+ scope.cancel()
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
index 2b4a7fb4803b..0a8210d6b319 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
@@ -32,7 +32,7 @@ class ConditionExtensionsTest : SysuiTestCase() {
fun flowInitiallyTrue() =
testScope.runTest {
val flow = flowOf(true)
- val condition = flow.toCondition(this)
+ val condition = flow.toCondition(scope = this, Condition.START_EAGERLY)
runCurrent()
assertThat(condition.isConditionSet).isFalse()
@@ -47,7 +47,7 @@ class ConditionExtensionsTest : SysuiTestCase() {
fun flowInitiallyFalse() =
testScope.runTest {
val flow = flowOf(false)
- val condition = flow.toCondition(this)
+ val condition = flow.toCondition(scope = this, Condition.START_EAGERLY)
runCurrent()
assertThat(condition.isConditionSet).isFalse()
@@ -62,7 +62,7 @@ class ConditionExtensionsTest : SysuiTestCase() {
fun emptyFlowWithNoInitialValue() =
testScope.runTest {
val flow = emptyFlow<Boolean>()
- val condition = flow.toCondition(this)
+ val condition = flow.toCondition(scope = this, Condition.START_EAGERLY)
condition.start()
runCurrent()
@@ -74,7 +74,12 @@ class ConditionExtensionsTest : SysuiTestCase() {
fun emptyFlowWithInitialValueOfTrue() =
testScope.runTest {
val flow = emptyFlow<Boolean>()
- val condition = flow.toCondition(scope = this, initialValue = true)
+ val condition =
+ flow.toCondition(
+ scope = this,
+ strategy = Condition.START_EAGERLY,
+ initialValue = true
+ )
condition.start()
runCurrent()
@@ -86,7 +91,12 @@ class ConditionExtensionsTest : SysuiTestCase() {
fun emptyFlowWithInitialValueOfFalse() =
testScope.runTest {
val flow = emptyFlow<Boolean>()
- val condition = flow.toCondition(scope = this, initialValue = false)
+ val condition =
+ flow.toCondition(
+ scope = this,
+ strategy = Condition.START_EAGERLY,
+ initialValue = false
+ )
condition.start()
runCurrent()
@@ -98,7 +108,7 @@ class ConditionExtensionsTest : SysuiTestCase() {
fun conditionUpdatesWhenFlowEmitsNewValue() =
testScope.runTest {
val flow = MutableStateFlow(false)
- val condition = flow.toCondition(this)
+ val condition = flow.toCondition(scope = this, strategy = Condition.START_EAGERLY)
condition.start()
runCurrent()
@@ -120,7 +130,7 @@ class ConditionExtensionsTest : SysuiTestCase() {
fun stoppingConditionUnsubscribesFromFlow() =
testScope.runTest {
val flow = MutableSharedFlow<Boolean>()
- val condition = flow.toCondition(this)
+ val condition = flow.toCondition(scope = this, strategy = Condition.START_EAGERLY)
runCurrent()
assertThat(flow.subscriptionCount.value).isEqualTo(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
index aa1636d8a030..de5824d1f463 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
@@ -39,12 +39,15 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
import java.util.HashSet;
+import kotlinx.coroutines.CoroutineScope;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class ConditionMonitorTest extends SysuiTestCase {
@@ -54,15 +57,18 @@ public class ConditionMonitorTest extends SysuiTestCase {
private HashSet<Condition> mConditions;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+ @Mock
+ private CoroutineScope mScope;
+
private Monitor mConditionMonitor;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mCondition1 = spy(new FakeCondition());
- mCondition2 = spy(new FakeCondition());
- mCondition3 = spy(new FakeCondition());
+ mCondition1 = spy(new FakeCondition(mScope));
+ mCondition2 = spy(new FakeCondition(mScope));
+ mCondition3 = spy(new FakeCondition(mScope));
mConditions = new HashSet<>(Arrays.asList(mCondition1, mCondition2, mCondition3));
mConditionMonitor = new Monitor(mExecutor);
@@ -396,7 +402,7 @@ public class ConditionMonitorTest extends SysuiTestCase {
@Test
public void unsetCondition_shouldNotAffectValue() {
- final FakeCondition settableCondition = new FakeCondition(null, false);
+ final FakeCondition settableCondition = new FakeCondition(mScope, null, false);
mCondition1.fakeUpdateCondition(true);
mCondition2.fakeUpdateCondition(true);
mCondition3.fakeUpdateCondition(true);
@@ -414,7 +420,7 @@ public class ConditionMonitorTest extends SysuiTestCase {
@Test
public void setUnsetCondition_shouldAffectValue() {
- final FakeCondition settableCondition = new FakeCondition(null, false);
+ final FakeCondition settableCondition = new FakeCondition(mScope, null, false);
mCondition1.fakeUpdateCondition(true);
mCondition2.fakeUpdateCondition(true);
mCondition3.fakeUpdateCondition(true);
@@ -443,7 +449,7 @@ public class ConditionMonitorTest extends SysuiTestCase {
@Test
public void clearingOverridingCondition_shouldBeExcluded() {
- final FakeCondition overridingCondition = new FakeCondition(true, true);
+ final FakeCondition overridingCondition = new FakeCondition(mScope, true, true);
mCondition1.fakeUpdateCondition(false);
mCondition2.fakeUpdateCondition(false);
mCondition3.fakeUpdateCondition(false);
@@ -466,7 +472,7 @@ public class ConditionMonitorTest extends SysuiTestCase {
@Test
public void settingUnsetOverridingCondition_shouldBeIncluded() {
- final FakeCondition overridingCondition = new FakeCondition(null, true);
+ final FakeCondition overridingCondition = new FakeCondition(mScope, null, true);
mCondition1.fakeUpdateCondition(false);
mCondition2.fakeUpdateCondition(false);
mCondition3.fakeUpdateCondition(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
index 8443221e8b7a..6efade9c9361 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
@@ -34,15 +34,23 @@ import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import kotlinx.coroutines.CoroutineScope;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class ConditionTest extends SysuiTestCase {
+ @Mock
+ CoroutineScope mScope;
+
private FakeCondition mCondition;
@Before
public void setup() {
- mCondition = spy(new FakeCondition());
+ MockitoAnnotations.initMocks(this);
+ mCondition = spy(new FakeCondition(mScope));
}
@Test
@@ -152,168 +160,4 @@ public class ConditionTest extends SysuiTestCase {
mCondition.clearCondition();
assertThat(mCondition.isConditionSet()).isFalse();
}
-
- @Test
- public void combineConditionsWithOr_allFalse_reportsNotMet() {
- mCondition.fakeUpdateCondition(false);
-
- final Condition combinedCondition = mCondition.or(
- new FakeCondition(/* initialValue= */ false));
-
- final Condition.Callback callback = mock(
- Condition.Callback.class);
- combinedCondition.addCallback(callback);
-
- assertThat(combinedCondition.isConditionSet()).isTrue();
- assertThat(combinedCondition.isConditionMet()).isFalse();
- verify(callback, times(1)).onConditionChanged(combinedCondition);
- }
-
- @Test
- public void combineConditionsWithOr_allTrue_reportsMet() {
- mCondition.fakeUpdateCondition(true);
-
- final Condition combinedCondition = mCondition.or(
- new FakeCondition(/* initialValue= */ true));
-
- final Condition.Callback callback = mock(
- Condition.Callback.class);
- combinedCondition.addCallback(callback);
-
- assertThat(combinedCondition.isConditionSet()).isTrue();
- assertThat(combinedCondition.isConditionMet()).isTrue();
- verify(callback, times(1)).onConditionChanged(combinedCondition);
- }
-
- @Test
- public void combineConditionsWithOr_singleTrue_reportsMet() {
- mCondition.fakeUpdateCondition(false);
-
- final Condition combinedCondition = mCondition.or(
- new FakeCondition(/* initialValue= */ true));
-
- final Condition.Callback callback = mock(
- Condition.Callback.class);
- combinedCondition.addCallback(callback);
-
- assertThat(combinedCondition.isConditionSet()).isTrue();
- assertThat(combinedCondition.isConditionMet()).isTrue();
- verify(callback, times(1)).onConditionChanged(combinedCondition);
- }
-
- @Test
- public void combineConditionsWithOr_unknownAndTrue_reportsMet() {
- mCondition.fakeUpdateCondition(true);
-
- // Combine with an unset condition.
- final Condition combinedCondition = mCondition.or(
- new FakeCondition(/* initialValue= */ null));
-
- final Condition.Callback callback = mock(
- Condition.Callback.class);
- combinedCondition.addCallback(callback);
-
- assertThat(combinedCondition.isConditionSet()).isTrue();
- assertThat(combinedCondition.isConditionMet()).isTrue();
- verify(callback, times(1)).onConditionChanged(combinedCondition);
- }
-
- @Test
- public void combineConditionsWithOr_unknownAndFalse_reportsNotMet() {
- mCondition.fakeUpdateCondition(false);
-
- // Combine with an unset condition.
- final Condition combinedCondition = mCondition.or(
- new FakeCondition(/* initialValue= */ null));
-
- final Condition.Callback callback = mock(
- Condition.Callback.class);
- combinedCondition.addCallback(callback);
-
- assertThat(combinedCondition.isConditionSet()).isFalse();
- assertThat(combinedCondition.isConditionMet()).isFalse();
- verify(callback, never()).onConditionChanged(combinedCondition);
- }
-
- @Test
- public void combineConditionsWithAnd_allFalse_reportsNotMet() {
- mCondition.fakeUpdateCondition(false);
-
- final Condition combinedCondition = mCondition.and(
- new FakeCondition(/* initialValue= */ false));
-
- final Condition.Callback callback = mock(
- Condition.Callback.class);
- combinedCondition.addCallback(callback);
-
- assertThat(combinedCondition.isConditionSet()).isTrue();
- assertThat(combinedCondition.isConditionMet()).isFalse();
- verify(callback, times(1)).onConditionChanged(combinedCondition);
- }
-
- @Test
- public void combineConditionsWithAnd_allTrue_reportsMet() {
- mCondition.fakeUpdateCondition(true);
-
- final Condition combinedCondition = mCondition.and(
- new FakeCondition(/* initialValue= */ true));
-
- final Condition.Callback callback = mock(
- Condition.Callback.class);
- combinedCondition.addCallback(callback);
-
- assertThat(combinedCondition.isConditionSet()).isTrue();
- assertThat(combinedCondition.isConditionMet()).isTrue();
- verify(callback, times(1)).onConditionChanged(combinedCondition);
- }
-
- @Test
- public void combineConditionsWithAnd_singleTrue_reportsNotMet() {
- mCondition.fakeUpdateCondition(true);
-
- final Condition combinedCondition = mCondition.and(
- new FakeCondition(/* initialValue= */ false));
-
- final Condition.Callback callback = mock(
- Condition.Callback.class);
- combinedCondition.addCallback(callback);
-
- assertThat(combinedCondition.isConditionSet()).isTrue();
- assertThat(combinedCondition.isConditionMet()).isFalse();
- verify(callback, times(1)).onConditionChanged(combinedCondition);
- }
-
- @Test
- public void combineConditionsWithAnd_unknownAndTrue_reportsNotMet() {
- mCondition.fakeUpdateCondition(true);
-
- // Combine with an unset condition.
- final Condition combinedCondition = mCondition.and(
- new FakeCondition(/* initialValue= */ null));
-
- final Condition.Callback callback = mock(
- Condition.Callback.class);
- combinedCondition.addCallback(callback);
-
- assertThat(combinedCondition.isConditionSet()).isFalse();
- assertThat(combinedCondition.isConditionMet()).isFalse();
- verify(callback, never()).onConditionChanged(combinedCondition);
- }
-
- @Test
- public void combineConditionsWithAnd_unknownAndFalse_reportsMet() {
- mCondition.fakeUpdateCondition(false);
-
- // Combine with an unset condition.
- final Condition combinedCondition = mCondition.and(
- new FakeCondition(/* initialValue= */ null));
-
- final Condition.Callback callback = mock(
- Condition.Callback.class);
- combinedCondition.addCallback(callback);
-
- assertThat(combinedCondition.isConditionSet()).isTrue();
- assertThat(combinedCondition.isConditionMet()).isFalse();
- verify(callback, times(1)).onConditionChanged(combinedCondition);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/FakeCondition.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/FakeCondition.java
index 55a6d39d4644..a325cbf25ffe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/FakeCondition.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/FakeCondition.java
@@ -16,21 +16,19 @@
package com.android.systemui.shared.condition;
+import kotlinx.coroutines.CoroutineScope;
+
/**
* Fake implementation of {@link Condition}, and provides a way for tests to update
* condition fulfillment.
*/
public class FakeCondition extends Condition {
- FakeCondition() {
- super();
- }
-
- FakeCondition(Boolean initialValue) {
- super(initialValue, false);
+ FakeCondition(CoroutineScope scope) {
+ super(scope);
}
- FakeCondition(Boolean initialValue, boolean overriding) {
- super(initialValue, overriding);
+ FakeCondition(CoroutineScope scope, Boolean initialValue, boolean overriding) {
+ super(scope, initialValue, overriding);
}
@Override
@@ -41,6 +39,11 @@ public class FakeCondition extends Condition {
public void stop() {
}
+ @Override
+ protected int getStartStrategy() {
+ return START_EAGERLY;
+ }
+
public void fakeUpdateCondition(boolean isConditionMet) {
updateCondition(isConditionMet);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
index 5fc0ffe42f55..8cb530c355bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
@@ -4,7 +4,7 @@ import android.testing.AndroidTestingRunner
import android.util.DisplayMetrics
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.log.LogBuffer
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
import com.android.systemui.statusbar.phone.LockscreenGestureLogger
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
index 5431eba8441c..c7ea09cb519d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
@@ -70,7 +70,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
index 9441d49d454a..d5689dcb3173 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
@@ -48,7 +48,7 @@ import com.android.settingslib.SignalIcon.MobileIconGroup;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
index 4c1f0a8a1066..35b9814cd81d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
@@ -43,7 +43,7 @@ import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.log.LogBuffer;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
index bef9fcb5697c..a37c38669bfd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
@@ -19,9 +19,9 @@ package com.android.systemui.statusbar.notification
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.statusbar.StatusBarState
import com.google.common.truth.Truth.assertThat
import org.junit.Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
index a1168f809971..f0abf2f4a24f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
@@ -32,9 +32,9 @@ import android.util.Property;
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ViewState;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 2831d2fad02a..163369f0412f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -41,6 +41,7 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.domain.interactor.BurnInInteractor;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -92,6 +93,7 @@ public class DozeServiceHostTest extends SysuiTestCase {
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private AuthController mAuthController;
@Mock private DozeHost.Callback mCallback;
+ @Mock private BurnInInteractor mBurnInInteractor;
@Before
public void setup() {
@@ -102,7 +104,8 @@ public class DozeServiceHostTest extends SysuiTestCase {
() -> mAssistManager, mDozeScrimController,
mKeyguardUpdateMonitor, mPulseExpansionHandler,
mNotificationShadeWindowController, mNotificationWakeUpCoordinator,
- mAuthController, mNotificationIconAreaController);
+ mAuthController, mNotificationIconAreaController,
+ mBurnInInteractor);
mDozeServiceHost.initialize(
mCentralSurfaces,
@@ -213,4 +216,12 @@ public class DozeServiceHostTest extends SysuiTestCase {
assertFalse(mDozeServiceHost.isPulsePending());
verify(mDozeScrimController).pulseOutNow();
}
+ @Test
+ public void dozeTimeTickSentTBurnInInteractor() {
+ // WHEN dozeTimeTick
+ mDozeServiceHost.dozeTimeTick();
+
+ // THEN burnInInteractor's dozeTimeTick is updated
+ verify(mBurnInInteractor).dozeTimeTick();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
index c282c1ef0cf6..b80b825d87dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
@@ -21,8 +21,6 @@ import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.StatusBarIconView
-import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
-import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
@@ -51,7 +49,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateWidthFor_oneIcon_widthForOneIcon() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10)
+ iconContainer.setIconSize(10);
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f),
/* actual= */ 30f)
@@ -61,7 +59,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateWidthFor_fourIcons_widthForFourIcons() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10)
+ iconContainer.setIconSize(10);
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f),
/* actual= */ 60f)
@@ -71,7 +69,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateWidthFor_fiveIcons_widthForFourIcons() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10)
+ iconContainer.setIconSize(10);
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f),
/* actual= */ 60f)
}
@@ -80,7 +78,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateIconXTranslations_shortShelfOneIcon_atCorrectXWithoutOverflowDot() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10)
+ iconContainer.setIconSize(10);
val icon = mockStatusBarIcon()
iconContainer.addView(icon)
@@ -101,7 +99,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateIconXTranslations_shortShelfFourIcons_atCorrectXWithoutOverflowDot() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10)
+ iconContainer.setIconSize(10);
val iconOne = mockStatusBarIcon()
val iconTwo = mockStatusBarIcon()
@@ -130,7 +128,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateIconXTranslations_shortShelfFiveIcons_atCorrectXWithOverflowDot() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10)
+ iconContainer.setIconSize(10);
val iconOne = mockStatusBarIcon()
val iconTwo = mockStatusBarIcon()
@@ -156,55 +154,6 @@ class NotificationIconContainerTest : SysuiTestCase() {
}
@Test
- fun calculateIconXTranslations_givenWidthEnoughForThreeIcons_atCorrectXWithoutOverflowDot() {
- iconContainer.setActualPaddingStart(0f)
- iconContainer.setActualPaddingEnd(0f)
- iconContainer.setActualLayoutWidth(30)
- iconContainer.setIconSize(10)
-
- val iconOne = mockStatusBarIcon()
- val iconTwo = mockStatusBarIcon()
- val iconThree = mockStatusBarIcon()
-
- iconContainer.addView(iconOne)
- iconContainer.addView(iconTwo)
- iconContainer.addView(iconThree)
- assertEquals(3, iconContainer.childCount)
-
- iconContainer.calculateIconXTranslations()
- assertEquals(0f, iconContainer.getIconState(iconOne).xTranslation)
- assertEquals(10f, iconContainer.getIconState(iconTwo).xTranslation)
- assertEquals(20f, iconContainer.getIconState(iconThree).xTranslation)
- assertFalse(iconContainer.areIconsOverflowing())
- }
-
- @Test
- fun calculateIconXTranslations_givenWidthNotEnoughForFourIcons_atCorrectXWithOverflowDot() {
- iconContainer.setActualPaddingStart(0f)
- iconContainer.setActualPaddingEnd(0f)
- iconContainer.setActualLayoutWidth(35)
- iconContainer.setIconSize(10)
-
- val iconOne = mockStatusBarIcon()
- val iconTwo = mockStatusBarIcon()
- val iconThree = mockStatusBarIcon()
- val iconFour = mockStatusBarIcon()
-
- iconContainer.addView(iconOne)
- iconContainer.addView(iconTwo)
- iconContainer.addView(iconThree)
- iconContainer.addView(iconFour)
- assertEquals(4, iconContainer.childCount)
-
- iconContainer.calculateIconXTranslations()
- assertEquals(0f, iconContainer.getIconState(iconOne).xTranslation)
- assertEquals(10f, iconContainer.getIconState(iconTwo).xTranslation)
- assertEquals(STATE_DOT, iconContainer.getIconState(iconThree).visibleState)
- assertEquals(STATE_HIDDEN, iconContainer.getIconState(iconFour).visibleState)
- assertTrue(iconContainer.areIconsOverflowing())
- }
-
- @Test
fun shouldForceOverflow_appearingAboveSpeedBump_true() {
val forceOverflow = iconContainer.shouldForceOverflow(
/* i= */ 1,
@@ -212,7 +161,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
/* iconAppearAmount= */ 1f,
/* maxVisibleIcons= */ 5
)
- assertTrue(forceOverflow)
+ assertTrue(forceOverflow);
}
@Test
@@ -223,7 +172,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
/* iconAppearAmount= */ 0f,
/* maxVisibleIcons= */ 5
)
- assertTrue(forceOverflow)
+ assertTrue(forceOverflow);
}
@Test
@@ -234,7 +183,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
/* iconAppearAmount= */ 0f,
/* maxVisibleIcons= */ 5
)
- assertFalse(forceOverflow)
+ assertFalse(forceOverflow);
}
@Test
@@ -261,17 +210,6 @@ class NotificationIconContainerTest : SysuiTestCase() {
}
@Test
- fun isOverflowing_lastChildXGreaterThanDotX_true() {
- val isOverflowing = iconContainer.isOverflowing(
- /* isLastChild= */ true,
- /* translationX= */ 9f,
- /* layoutEnd= */ 10f,
- /* iconSize= */ 2f,
- )
- assertTrue(isOverflowing)
- }
-
- @Test
fun isOverflowing_lastChildXGreaterThanLayoutEnd_true() {
val isOverflowing = iconContainer.isOverflowing(
/* isLastChild= */ true,
@@ -315,7 +253,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
assertTrue(isOverflowing)
}
- private fun mockStatusBarIcon(): StatusBarIconView {
+ private fun mockStatusBarIcon() : StatusBarIconView {
val iconView = mock(StatusBarIconView::class.java)
whenever(iconView.width).thenReturn(10)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
index 3a0a94ddd511..9bc49ae02436 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
@@ -20,7 +20,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
@@ -43,15 +43,39 @@ class CollapsedStatusBarFragmentLoggerTest : SysuiTestCase() {
fun logDisableFlagChange_bufferHasStates() {
val state = DisableFlagsLogger.DisableState(0, 1)
- logger.logDisableFlagChange(state, state)
+ logger.logDisableFlagChange(state)
val stringWriter = StringWriter()
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
val actualString = stringWriter.toString()
- val expectedLogString = disableFlagsLogger.getDisableFlagsString(
- old = null, new = state, newAfterLocalModification = state
- )
+ val expectedLogString =
+ disableFlagsLogger.getDisableFlagsString(
+ old = null,
+ new = state,
+ newAfterLocalModification = null,
+ )
assertThat(actualString).contains(expectedLogString)
}
+
+ @Test
+ fun logVisibilityModel_bufferCorrect() {
+ logger.logVisibilityModel(
+ StatusBarVisibilityModel(
+ showClock = false,
+ showNotificationIcons = true,
+ showOngoingCallChip = false,
+ showSystemInfo = true,
+ )
+ )
+
+ val stringWriter = StringWriter()
+ buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+ val actualString = stringWriter.toString()
+
+ assertThat(actualString).contains("showClock=false")
+ assertThat(actualString).contains("showNotificationIcons=true")
+ assertThat(actualString).contains("showOngoingCallChip=false")
+ assertThat(actualString).contains("showSystemInfo=true")
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 2a3c775eaf54..21769922c899 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone.fragment;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED;
+import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
@@ -52,9 +54,9 @@ import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.log.LogBuffer;
+import com.android.systemui.log.LogcatEchoTracker;
import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.plugins.log.LogBuffer;
-import com.android.systemui.plugins.log.LogcatEchoTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.ShadeViewController;
@@ -93,6 +95,7 @@ import java.util.List;
public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
private NotificationIconAreaController mMockNotificationAreaController;
+ private ShadeExpansionStateManager mShadeExpansionStateManager;
private View mNotificationAreaInner;
private OngoingCallController mOngoingCallController;
private SystemStatusAnimationScheduler mAnimationScheduler;
@@ -173,6 +176,10 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
+
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
@Test
@@ -278,6 +285,10 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
+
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
+
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
}
@Test
@@ -291,6 +302,70 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, getClockView().getVisibility());
+
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
+
+ assertEquals(View.GONE, getClockView().getVisibility());
+ }
+
+ @Test
+ public void disable_shadeOpenAndShouldHide_everythingHidden() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN the shade is open and configured to hide the status bar icons
+ mShadeExpansionStateManager.updateState(STATE_OPEN);
+ when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // THEN all views are hidden
+ assertEquals(View.INVISIBLE, getClockView().getVisibility());
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
+ public void disable_shadeOpenButNotShouldHide_everythingShown() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN the shade is open but *not* configured to hide the status bar icons
+ mShadeExpansionStateManager.updateState(STATE_OPEN);
+ when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(false);
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // THEN all views are shown
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ /** Regression test for b/279790651. */
+ @Test
+ public void disable_shadeOpenAndShouldHide_thenShadeNotOpenAndDozingUpdate_everythingShown() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN the shade is open and configured to hide the status bar icons
+ mShadeExpansionStateManager.updateState(STATE_OPEN);
+ when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // THEN all views are hidden
+ assertEquals(View.INVISIBLE, getClockView().getVisibility());
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
+
+ // WHEN the shade is updated to no longer be open
+ mShadeExpansionStateManager.updateState(STATE_CLOSED);
+
+ // AND we internally request an update via dozing change
+ fragment.onDozingChanged(true);
+
+ // THEN all views are shown
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
@Test
@@ -323,7 +398,6 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
assertEquals(View.VISIBLE,
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
-
}
@Test
@@ -356,20 +430,26 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
public void disable_ongoingCallEnded_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
- when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
-
// Ongoing call started
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
assertEquals(View.VISIBLE,
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
// Ongoing call ended
when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
-
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.GONE,
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+
+ // Ongoing call started
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ assertEquals(View.VISIBLE,
+ mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
}
@Test
@@ -494,6 +574,8 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager);
mSecureSettings = mock(SecureSettings.class);
+ mShadeExpansionStateManager = new ShadeExpansionStateManager();
+
setUpNotificationIconAreaController();
return new CollapsedStatusBarFragment(
mStatusBarFragmentComponentFactory,
@@ -501,7 +583,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
mAnimationScheduler,
mLocationPublisher,
mMockNotificationAreaController,
- new ShadeExpansionStateManager(),
+ mShadeExpansionStateManager,
mock(FeatureFlags.class),
mStatusBarIconController,
mIconManagerFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
new file mode 100644
index 000000000000..8e789cb2cae6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.fragment
+
+import android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS
+import android.app.StatusBarManager.DISABLE_CLOCK
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
+import android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP
+import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.phone.fragment.StatusBarVisibilityModel.Companion.createDefaultModel
+import com.android.systemui.statusbar.phone.fragment.StatusBarVisibilityModel.Companion.createModelFromFlags
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+@SmallTest
+class StatusBarVisibilityModelTest : SysuiTestCase() {
+ @Test
+ fun createDefaultModel_everythingEnabled() {
+ val result = createDefaultModel()
+
+ val expected =
+ StatusBarVisibilityModel(
+ showClock = true,
+ showNotificationIcons = true,
+ showOngoingCallChip = true,
+ showSystemInfo = true,
+ )
+
+ assertThat(result).isEqualTo(expected)
+ }
+
+ @Test
+ fun createModelFromFlags_clockNotDisabled_showClockTrue() {
+ val result = createModelFromFlags(disabled1 = 0, disabled2 = 0)
+
+ assertThat(result.showClock).isTrue()
+ }
+
+ @Test
+ fun createModelFromFlags_clockDisabled_showClockFalse() {
+ val result = createModelFromFlags(disabled1 = DISABLE_CLOCK, disabled2 = 0)
+
+ assertThat(result.showClock).isFalse()
+ }
+
+ @Test
+ fun createModelFromFlags_notificationIconsNotDisabled_showNotificationIconsTrue() {
+ val result = createModelFromFlags(disabled1 = 0, disabled2 = 0)
+
+ assertThat(result.showNotificationIcons).isTrue()
+ }
+
+ @Test
+ fun createModelFromFlags_notificationIconsDisabled_showNotificationIconsFalse() {
+ val result = createModelFromFlags(disabled1 = DISABLE_NOTIFICATION_ICONS, disabled2 = 0)
+
+ assertThat(result.showNotificationIcons).isFalse()
+ }
+
+ @Test
+ fun createModelFromFlags_ongoingCallChipNotDisabled_showOngoingCallChipTrue() {
+ val result = createModelFromFlags(disabled1 = 0, disabled2 = 0)
+
+ assertThat(result.showOngoingCallChip).isTrue()
+ }
+
+ @Test
+ fun createModelFromFlags_ongoingCallChipDisabled_showOngoingCallChipFalse() {
+ val result = createModelFromFlags(disabled1 = DISABLE_ONGOING_CALL_CHIP, disabled2 = 0)
+
+ assertThat(result.showOngoingCallChip).isFalse()
+ }
+
+ @Test
+ fun createModelFromFlags_systemInfoAndIconsNotDisabled_showSystemInfoTrue() {
+ val result = createModelFromFlags(disabled1 = 0, disabled2 = 0)
+
+ assertThat(result.showSystemInfo).isTrue()
+ }
+
+ @Test
+ fun createModelFromFlags_disable1SystemInfoDisabled_showSystemInfoFalse() {
+ val result = createModelFromFlags(disabled1 = DISABLE_SYSTEM_INFO, disabled2 = 0)
+
+ assertThat(result.showSystemInfo).isFalse()
+ }
+
+ @Test
+ fun createModelFromFlags_disable2SystemIconsDisabled_showSystemInfoFalse() {
+ val result = createModelFromFlags(disabled1 = 0, disabled2 = DISABLE2_SYSTEM_ICONS)
+
+ assertThat(result.showSystemInfo).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
index 03cd94fa9d70..c43778a4ae51 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
@@ -18,7 +18,7 @@ package com.android.systemui.statusbar.pipeline.shared.data.model
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.log.LogMessageImpl
+import com.android.systemui.log.LogMessageImpl
import com.google.common.truth.Truth.assertThat
import org.junit.Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index d9d8b6345fcb..3b0d5120cca3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -585,8 +585,6 @@ public class SmartReplyViewTest extends SysuiTestCase {
// devices.
layout.setBaselineAligned(false);
- final boolean isRtl = mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-
// Add smart replies
Button previous = null;
SmartReplyView.SmartReplies smartReplies =
@@ -606,11 +604,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
if (previous != null) {
ViewGroup.MarginLayoutParams lp =
(ViewGroup.MarginLayoutParams) previous.getLayoutParams();
- if (isRtl) {
- lp.leftMargin = mSpacing;
- } else {
- lp.rightMargin = mSpacing;
- }
+ lp.setMarginEnd(mSpacing);
}
layout.addView(current);
previous = current;
@@ -634,11 +628,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
if (previous != null) {
ViewGroup.MarginLayoutParams lp =
(ViewGroup.MarginLayoutParams) previous.getLayoutParams();
- if (isRtl) {
- lp.leftMargin = mSpacing;
- } else {
- lp.rightMargin = mSpacing;
- }
+ lp.setMarginEnd(mSpacing);
}
layout.addView(current);
previous = current;
@@ -937,8 +927,8 @@ public class SmartReplyViewTest extends SysuiTestCase {
.collect(Collectors.toList());
Button singleLineButton = buttons.get(0);
Button doubleLineButton = buttons.get(1);
- Drawable singleLineDrawable = singleLineButton.getCompoundDrawables()[0]; // left drawable
- Drawable doubleLineDrawable = doubleLineButton.getCompoundDrawables()[0]; // left drawable
+ Drawable singleLineDrawable = singleLineButton.getCompoundDrawablesRelative()[0]; // start
+ Drawable doubleLineDrawable = doubleLineButton.getCompoundDrawablesRelative()[0]; // start
assertEquals(singleLineDrawable.getBounds().width(),
doubleLineDrawable.getBounds().width());
assertEquals(singleLineDrawable.getBounds().height(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
index 2e66b205bfd5..451424927b23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
@@ -19,9 +19,9 @@ package com.android.systemui.temporarydisplay
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.log.LogcatEchoTracker
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
index 5b431e72e2ac..09830413bdc8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
@@ -14,6 +14,8 @@
package com.android.systemui.animation
+import com.android.app.animation.Interpolators
+
/** A [LaunchAnimator] to be used in tests. */
fun fakeLaunchAnimator(): LaunchAnimator {
return LaunchAnimator(TEST_TIMINGS, TEST_INTERPOLATORS)
diff --git a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
deleted file mode 100644
index 715697d82cad..000000000000
--- a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
+++ /dev/null
@@ -1,293 +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.server.autofill;
-
-import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
-
-import static com.android.server.autofill.Helper.sVerbose;
-
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.AppGlobals;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.ICancellationSignal;
-import android.os.RemoteException;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.service.autofill.IFillCallback;
-import android.service.autofill.SaveInfo;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.Slog;
-import android.view.autofill.AutofillId;
-import android.view.autofill.IAutoFillManagerClient;
-import android.view.inputmethod.InlineSuggestionsRequest;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AndroidFuture;
-
-import java.util.List;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Maintains a client suggestions session with the
- * {@link android.view.autofill.AutofillRequestCallback} through the {@link IAutoFillManagerClient}.
- *
- */
-final class ClientSuggestionsSession {
-
- private static final String TAG = "ClientSuggestionsSession";
- private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 15 * DateUtils.SECOND_IN_MILLIS;
-
- private final int mSessionId;
- private final IAutoFillManagerClient mClient;
- private final Handler mHandler;
- private final ComponentName mComponentName;
-
- private final RemoteFillService.FillServiceCallbacks mCallbacks;
-
- private final Object mLock = new Object();
- @GuardedBy("mLock")
- private AndroidFuture<FillResponse> mPendingFillRequest;
- @GuardedBy("mLock")
- private int mPendingFillRequestId = INVALID_REQUEST_ID;
-
- ClientSuggestionsSession(int sessionId, IAutoFillManagerClient client, Handler handler,
- ComponentName componentName, RemoteFillService.FillServiceCallbacks callbacks) {
- mSessionId = sessionId;
- mClient = client;
- mHandler = handler;
- mComponentName = componentName;
- mCallbacks = callbacks;
- }
-
- void onFillRequest(int requestId, InlineSuggestionsRequest inlineRequest, int flags) {
- final AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
- final AtomicReference<AndroidFuture<FillResponse>> futureRef = new AtomicReference<>();
- final AndroidFuture<FillResponse> fillRequest = new AndroidFuture<>();
-
- mHandler.post(() -> {
- if (sVerbose) {
- Slog.v(TAG, "calling onFillRequest() for id=" + requestId);
- }
-
- try {
- mClient.requestFillFromClient(requestId, inlineRequest,
- new FillCallbackImpl(fillRequest, futureRef, cancellationSink));
- } catch (RemoteException e) {
- fillRequest.completeExceptionally(e);
- }
- });
-
- fillRequest.orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
- futureRef.set(fillRequest);
-
- synchronized (mLock) {
- mPendingFillRequest = fillRequest;
- mPendingFillRequestId = requestId;
- }
-
- fillRequest.whenComplete((res, err) -> mHandler.post(() -> {
- synchronized (mLock) {
- mPendingFillRequest = null;
- mPendingFillRequestId = INVALID_REQUEST_ID;
- }
- if (err == null) {
- processAutofillId(res);
- mCallbacks.onFillRequestSuccess(requestId, res,
- mComponentName.getPackageName(), flags);
- } else {
- Slog.e(TAG, "Error calling on client fill request", err);
- if (err instanceof TimeoutException) {
- dispatchCancellationSignal(cancellationSink.get());
- mCallbacks.onFillRequestTimeout(requestId);
- } else if (err instanceof CancellationException) {
- dispatchCancellationSignal(cancellationSink.get());
- } else {
- mCallbacks.onFillRequestFailure(requestId, err.getMessage());
- }
- }
- }));
- }
-
- /**
- * Gets the application info for the component.
- */
- @Nullable
- static ApplicationInfo getAppInfo(ComponentName comp, @UserIdInt int userId) {
- try {
- ApplicationInfo si = AppGlobals.getPackageManager().getApplicationInfo(
- comp.getPackageName(),
- PackageManager.GET_META_DATA,
- userId);
- if (si != null) {
- return si;
- }
- } catch (RemoteException e) {
- }
- return null;
- }
-
- /**
- * Gets the user-visible name of the application.
- */
- @Nullable
- @GuardedBy("mLock")
- static CharSequence getAppLabelLocked(Context context, ApplicationInfo appInfo) {
- return appInfo == null ? null : appInfo.loadSafeLabel(
- context.getPackageManager(), 0 /* do not ellipsize */,
- TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM);
- }
-
- /**
- * Gets the user-visible icon of the application.
- */
- @Nullable
- @GuardedBy("mLock")
- static Drawable getAppIconLocked(Context context, ApplicationInfo appInfo) {
- return appInfo == null ? null : appInfo.loadIcon(context.getPackageManager());
- }
-
- int cancelCurrentRequest() {
- synchronized (mLock) {
- return mPendingFillRequest != null && mPendingFillRequest.cancel(false)
- ? mPendingFillRequestId
- : INVALID_REQUEST_ID;
- }
- }
-
- /**
- * The {@link AutofillId} which the client gets from its view is not contain the session id,
- * but Autofill framework is using the {@link AutofillId} with a session id. So before using
- * those ids in the Autofill framework, applies the current session id.
- *
- * @param res which response need to apply for a session id
- */
- private void processAutofillId(FillResponse res) {
- if (res == null) {
- return;
- }
-
- final List<Dataset> datasets = res.getDatasets();
- if (datasets != null && !datasets.isEmpty()) {
- for (int i = 0; i < datasets.size(); i++) {
- final Dataset dataset = datasets.get(i);
- if (dataset != null) {
- applySessionId(dataset.getFieldIds());
- }
- }
- }
-
- final SaveInfo saveInfo = res.getSaveInfo();
- if (saveInfo != null) {
- applySessionId(saveInfo.getOptionalIds());
- applySessionId(saveInfo.getRequiredIds());
- applySessionId(saveInfo.getSanitizerValues());
- applySessionId(saveInfo.getTriggerId());
- }
- }
-
- private void applySessionId(List<AutofillId> ids) {
- if (ids == null || ids.isEmpty()) {
- return;
- }
-
- for (int i = 0; i < ids.size(); i++) {
- applySessionId(ids.get(i));
- }
- }
-
- private void applySessionId(AutofillId[][] ids) {
- if (ids == null) {
- return;
- }
- for (int i = 0; i < ids.length; i++) {
- applySessionId(ids[i]);
- }
- }
-
- private void applySessionId(AutofillId[] ids) {
- if (ids == null) {
- return;
- }
- for (int i = 0; i < ids.length; i++) {
- applySessionId(ids[i]);
- }
- }
-
- private void applySessionId(AutofillId id) {
- if (id == null) {
- return;
- }
- id.setSessionId(mSessionId);
- }
-
- private void dispatchCancellationSignal(@Nullable ICancellationSignal signal) {
- if (signal == null) {
- return;
- }
- try {
- signal.cancel();
- } catch (RemoteException e) {
- Slog.e(TAG, "Error requesting a cancellation", e);
- }
- }
-
- private class FillCallbackImpl extends IFillCallback.Stub {
- final AndroidFuture<FillResponse> mFillRequest;
- final AtomicReference<AndroidFuture<FillResponse>> mFutureRef;
- final AtomicReference<ICancellationSignal> mCancellationSink;
-
- FillCallbackImpl(AndroidFuture<FillResponse> fillRequest,
- AtomicReference<AndroidFuture<FillResponse>> futureRef,
- AtomicReference<ICancellationSignal> cancellationSink) {
- mFillRequest = fillRequest;
- mFutureRef = futureRef;
- mCancellationSink = cancellationSink;
- }
-
- @Override
- public void onCancellable(ICancellationSignal cancellation) {
- AndroidFuture<FillResponse> future = mFutureRef.get();
- if (future != null && future.isCancelled()) {
- dispatchCancellationSignal(cancellation);
- } else {
- mCancellationSink.set(cancellation);
- }
- }
-
- @Override
- public void onSuccess(FillResponse response) {
- mFillRequest.complete(response);
- }
-
- @Override
- public void onFailure(int requestId, CharSequence message) {
- String errorMessage = message == null ? "" : String.valueOf(message);
- mFillRequest.completeExceptionally(
- new RuntimeException(errorMessage));
- }
- }
-}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index f83d7342b6e3..3736262e0673 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -36,7 +36,6 @@ import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN;
-import static android.view.autofill.AutofillManager.FLAG_ENABLED_CLIENT_SUGGESTIONS;
import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
@@ -446,9 +445,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
*/
private final PccAssistDataReceiverImpl mPccAssistReceiver = new PccAssistDataReceiverImpl();
- @Nullable
- private ClientSuggestionsSession mClientSuggestionsSession;
-
private final ClassificationState mClassificationState = new ClassificationState();
// TODO(b/216576510): Share one BroadcastReceiver between all Sessions instead of creating a
@@ -590,9 +586,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
/** Whether the current {@link FillResponse} is expired. */
private boolean mExpiredResponse;
- /** Whether the client is using {@link android.view.autofill.AutofillRequestCallback}. */
- private boolean mClientSuggestionsEnabled;
-
/** Whether the fill dialog UI is disabled. */
private boolean mFillDialogDisabled;
}
@@ -623,21 +616,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
mWaitForInlineRequest = inlineSuggestionsRequest != null;
mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
- mWaitForInlineRequest = inlineSuggestionsRequest != null;
- maybeRequestFillFromServiceLocked();
+ maybeRequestFillLocked();
viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
}
} : null;
}
- void newAutofillRequestLocked(@Nullable InlineSuggestionsRequest inlineRequest) {
- mPendingFillRequest = null;
- mWaitForInlineRequest = inlineRequest != null;
- mPendingInlineSuggestionsRequest = inlineRequest;
- }
-
@GuardedBy("mLock")
- void maybeRequestFillFromServiceLocked() {
+ void maybeRequestFillLocked() {
if (mPendingFillRequest == null) {
return;
}
@@ -647,15 +633,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
- if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
- mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
- mPendingFillRequest.getFillContexts(),
- mPendingFillRequest.getHints(),
- mPendingFillRequest.getClientState(),
- mPendingFillRequest.getFlags(),
- mPendingInlineSuggestionsRequest,
- mPendingFillRequest.getDelayedFillIntentSender());
- }
+ mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
+ mPendingFillRequest.getFillContexts(),
+ mPendingFillRequest.getHints(),
+ mPendingFillRequest.getClientState(),
+ mPendingFillRequest.getFlags(),
+ mPendingInlineSuggestionsRequest,
+ mPendingFillRequest.getDelayedFillIntentSender());
}
mLastFillRequest = mPendingFillRequest;
@@ -777,7 +761,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
: mDelayedFillPendingIntent.getIntentSender());
mPendingFillRequest = request;
- maybeRequestFillFromServiceLocked();
+ maybeRequestFillLocked();
}
if (mActivityToken != null) {
@@ -1099,39 +1083,30 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
/**
- * Cancels the last request sent to the {@link #mRemoteFillService} or the
- * {@link #mClientSuggestionsSession}.
+ * Cancels the last request sent to the {@link #mRemoteFillService}.
*/
@GuardedBy("mLock")
private void cancelCurrentRequestLocked() {
- if (mRemoteFillService == null && mClientSuggestionsSession == null) {
- wtf(null, "cancelCurrentRequestLocked() called without a remote service or a "
- + "client suggestions session. mForAugmentedAutofillOnly: %s",
- mSessionFlags.mAugmentedAutofillOnly);
+ if (mRemoteFillService == null) {
+ wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
+ + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
return;
}
+ final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
- if (mRemoteFillService != null) {
- final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
-
- // Remove the FillContext as there will never be a response for the service
- if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
- final int numContexts = mContexts.size();
+ // Remove the FillContext as there will never be a response for the service
+ if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
+ final int numContexts = mContexts.size();
- // It is most likely the last context, hence search backwards
- for (int i = numContexts - 1; i >= 0; i--) {
- if (mContexts.get(i).getRequestId() == canceledRequest) {
- if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
- mContexts.remove(i);
- break;
- }
+ // It is most likely the last context, hence search backwards
+ for (int i = numContexts - 1; i >= 0; i--) {
+ if (mContexts.get(i).getRequestId() == canceledRequest) {
+ if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
+ mContexts.remove(i);
+ break;
}
}
}
-
- if (mClientSuggestionsSession != null) {
- mClientSuggestionsSession.cancelCurrentRequest();
- }
}
private boolean isViewFocusedLocked(int flags) {
@@ -1225,30 +1200,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
requestAssistStructureForPccLocked(flags | FLAG_PCC_DETECTION);
}
- // Only ask IME to create inline suggestions request when
- // 1. Autofill provider supports it or client enabled client suggestions.
- // 2. The render service is available.
- // 3. The view is focused. (The view may not be focused if the autofill is triggered
- // manually.)
+ // Only ask IME to create inline suggestions request if Autofill provider supports it and
+ // the render service is available except the autofill is triggered manually and the view
+ // is also not focused.
final RemoteInlineSuggestionRenderService remoteRenderService =
mService.getRemoteInlineSuggestionRenderServiceLocked();
- if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled)
- && remoteRenderService != null
- && (isViewFocusedLocked(flags) || (isRequestSupportFillDialog(flags)))) {
- final Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer;
- if (mSessionFlags.mClientSuggestionsEnabled) {
- final int finalRequestId = requestId;
- inlineSuggestionsRequestConsumer = (inlineSuggestionsRequest) -> {
- // Using client suggestions
- synchronized (mLock) {
- onClientFillRequestLocked(finalRequestId, inlineSuggestionsRequest);
- }
- viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
- };
- } else {
- inlineSuggestionsRequestConsumer = mAssistReceiver.newAutofillRequestLocked(
- viewState, /* isInlineRequest= */ true);
- }
+ if (mSessionFlags.mInlineSupportedByService
+ && remoteRenderService != null
+ && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
+ Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
+ mAssistReceiver.newAutofillRequestLocked(viewState,
+ /* isInlineRequest= */ true);
if (inlineSuggestionsRequestConsumer != null) {
final AutofillId focusedId = mCurrentViewId;
final int requestIdCopy = requestId;
@@ -1264,18 +1226,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
);
viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
}
- } else if (mSessionFlags.mClientSuggestionsEnabled) {
- // Request client suggestions for the dropdown mode
- onClientFillRequestLocked(requestId, null);
} else {
mAssistReceiver.newAutofillRequestLocked(viewState, /* isInlineRequest= */ false);
}
- if (mSessionFlags.mClientSuggestionsEnabled) {
- // Using client suggestions, unnecessary request AssistStructure
- return;
- }
-
// Now request the assist structure data.
requestAssistStructureLocked(requestId, flags);
}
@@ -1380,11 +1334,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mSessionFlags = new SessionFlags();
mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly;
mSessionFlags.mInlineSupportedByService = mService.isInlineSuggestionsEnabledLocked();
- if (mContext.checkCallingPermission(PROVIDE_OWN_AUTOFILL_SUGGESTIONS)
- == PackageManager.PERMISSION_GRANTED) {
- mSessionFlags.mClientSuggestionsEnabled =
- (mFlags & FLAG_ENABLED_CLIENT_SUGGESTIONS) != 0;
- }
setClientLocked(client);
}
@@ -1522,15 +1471,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (requestLog != null) {
requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
}
- processNullResponseOrFallbackLocked(requestId, requestFlags);
+ processNullResponseLocked(requestId, requestFlags);
return;
}
// TODO: Check if this is required. We can still present datasets to the user even if
// traditional field classification is disabled.
fieldClassificationIds = response.getFieldClassificationIds();
- if (!mSessionFlags.mClientSuggestionsEnabled && fieldClassificationIds != null
- && !mService.isFieldClassificationEnabledLocked()) {
+ if (fieldClassificationIds != null && !mService.isFieldClassificationEnabledLocked()) {
Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
processNullResponseLocked(requestId, requestFlags);
return;
@@ -1643,9 +1591,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|| (ArrayUtils.isEmpty(saveInfo.getOptionalIds())
&& ArrayUtils.isEmpty(saveInfo.getRequiredIds())
&& ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) == 0)))
- && (ArrayUtils.isEmpty(response.getFieldClassificationIds())
- || (!mSessionFlags.mClientSuggestionsEnabled
- && !mService.isFieldClassificationEnabledLocked())));
+ && (ArrayUtils.isEmpty(response.getFieldClassificationIds())));
}
}
@@ -1975,40 +1921,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
- @GuardedBy("mLock")
- private void processNullResponseOrFallbackLocked(int requestId, int flags) {
- if (!mSessionFlags.mClientSuggestionsEnabled) {
- processNullResponseLocked(requestId, flags);
- return;
- }
-
- // fallback to the default platform password manager
- mSessionFlags.mClientSuggestionsEnabled = false;
- mLastFillDialogTriggerIds = null;
- // Log the existing FillResponse event.
- mFillResponseEventLogger.logAndEndEvent();
-
- final InlineSuggestionsRequest inlineRequest =
- (mLastInlineSuggestionsRequest != null
- && mLastInlineSuggestionsRequest.first == requestId)
- ? mLastInlineSuggestionsRequest.second : null;
-
- // Start a new FillRequest logger for client suggestion fallback.
- mFillRequestEventLogger.startLogForNewRequest();
- mRequestCount++;
- mFillRequestEventLogger.maybeSetAppPackageUid(uid);
- mFillRequestEventLogger.maybeSetFlags(
- flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
- mFillRequestEventLogger.maybeSetRequestTriggerReason(
- TRIGGER_REASON_NORMAL_TRIGGER);
- mFillRequestEventLogger.maybeSetIsClientSuggestionFallback(true);
-
- mAssistReceiver.newAutofillRequestLocked(inlineRequest);
- requestAssistStructureLocked(requestId,
- flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
- return;
- }
-
// FillServiceCallbacks
@Override
@SuppressWarnings("GuardedBy")
@@ -4205,22 +4117,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
filterText = value.getTextValue().toString();
}
- final CharSequence targetLabel;
- final Drawable targetIcon;
- synchronized (mLock) {
- if (mSessionFlags.mClientSuggestionsEnabled) {
- final ApplicationInfo appInfo = ClientSuggestionsSession.getAppInfo(mComponentName,
- mService.getUserId());
- targetLabel = ClientSuggestionsSession.getAppLabelLocked(
- mService.getMaster().getContext(), appInfo);
- targetIcon = ClientSuggestionsSession.getAppIconLocked(
- mService.getMaster().getContext(), appInfo);
- } else {
- targetLabel = mService.getServiceLabelLocked();
- targetIcon = mService.getServiceIconLocked();
- }
+ final CharSequence serviceLabel;
+ final Drawable serviceIcon;
+ synchronized (this.mService.mLock) {
+ serviceLabel = mService.getServiceLabelLocked();
+ serviceIcon = mService.getServiceIconLocked();
}
- if (targetLabel == null || targetIcon == null) {
+ if (serviceLabel == null || serviceIcon == null) {
wtf(null, "onFillReady(): no service label or icon");
return;
}
@@ -4281,7 +4184,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
getUiForShowing().showFillUi(filledId, response, filterText,
mService.getServicePackageName(), mComponentName,
- targetLabel, targetIcon, this, mContext, id, mCompatMode);
+ serviceLabel, serviceIcon, this, mContext, id, mCompatMode);
synchronized (mLock) {
mPresentationStatsEventLogger.maybeSetCountShown(
@@ -4477,17 +4380,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return false;
}
- final InlineSuggestionsRequest request = inlineSuggestionsRequest.get();
- if (mSessionFlags.mClientSuggestionsEnabled && !request.isClientSupported()
- || !mSessionFlags.mClientSuggestionsEnabled && !request.isServiceSupported()) {
- if (sDebug) {
- Slog.d(TAG, "Inline suggestions not supported for "
- + (mSessionFlags.mClientSuggestionsEnabled ? "client" : "service")
- + ". Falling back to dropdown.");
- }
- return false;
- }
-
final RemoteInlineSuggestionRenderService remoteRenderService =
mService.getRemoteInlineSuggestionRenderServiceLocked();
if (remoteRenderService == null) {
@@ -4502,8 +4394,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
final InlineFillUi.InlineFillUiInfo inlineFillUiInfo =
- new InlineFillUi.InlineFillUiInfo(request, focusedId,
- filterText, remoteRenderService, userId, id);
+ new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId,
+ filterText, remoteRenderService, userId, id);
InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response,
new InlineFillUi.InlineSuggestionUiCallback() {
@Override
@@ -5154,26 +5046,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
- @GuardedBy("mLock")
- private void onClientFillRequestLocked(int requestId,
- InlineSuggestionsRequest inlineSuggestionsRequest) {
- if (mClientSuggestionsSession == null) {
- mClientSuggestionsSession = new ClientSuggestionsSession(id, mClient, mHandler,
- mComponentName, this);
- }
-
- if (mContexts == null) {
- mContexts = new ArrayList<>(1);
- }
- mContexts.add(new FillContext(requestId, new AssistStructure(), mCurrentViewId));
-
- if (inlineSuggestionsRequest != null && !inlineSuggestionsRequest.isClientSupported()) {
- inlineSuggestionsRequest = null;
- }
-
- mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags);
- }
-
/**
* The result of checking whether to show the save dialog, when session can be saved.
*
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 0172eaf03fa7..c8db662a7f49 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -54,6 +54,7 @@ import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.bluetooth.BluetoothDevice;
import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
import android.companion.DeviceNotAssociatedException;
@@ -234,7 +235,7 @@ public class CompanionDeviceManagerService extends SystemService {
loadAssociationsFromDisk();
mAssociationStore.registerListener(mAssociationStoreChangeListener);
- mDevicePresenceMonitor = new CompanionDevicePresenceMonitor(
+ mDevicePresenceMonitor = new CompanionDevicePresenceMonitor(mUserManager,
mAssociationStore, mDevicePresenceCallback);
mAssociationRequestsProcessor = new AssociationRequestsProcessor(
@@ -322,6 +323,23 @@ public class CompanionDeviceManagerService extends SystemService {
MINUTES.toMillis(10));
}
+ @Override
+ public void onUserUnlocked(@NonNull TargetUser user) {
+ // Notify and bind the app after the phone is unlocked.
+ final int userId = user.getUserIdentifier();
+ final Set<BluetoothDevice> blueToothDevices =
+ mDevicePresenceMonitor.getPendingConnectedDevices().get(userId);
+ if (blueToothDevices != null) {
+ for (BluetoothDevice bluetoothDevice : blueToothDevices) {
+ for (AssociationInfo ai:
+ mAssociationStore.getAssociationsByAddress(bluetoothDevice.getAddress())) {
+ Slog.i(TAG, "onUserUnlocked, device id( " + ai.getId() + " ) is connected");
+ mDevicePresenceMonitor.onBluetoothCompanionDeviceConnected(ai.getId());
+ }
+ }
+ }
+ }
+
@NonNull
AssociationInfo getAssociationWithCallerChecks(
@UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress) {
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
index 6f99d8677646..e436e9300fb5 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
@@ -128,9 +128,9 @@ public class CallMetadataSyncConnectionService extends ConnectionService {
private static final class CallMetadataSyncConnectionIdentifier {
private final int mAssociationId;
- private final long mCallId;
+ private final String mCallId;
- CallMetadataSyncConnectionIdentifier(int associationId, long callId) {
+ CallMetadataSyncConnectionIdentifier(int associationId, String callId) {
mAssociationId = associationId;
mCallId = callId;
}
@@ -139,7 +139,7 @@ public class CallMetadataSyncConnectionService extends ConnectionService {
return mAssociationId;
}
- public long getCallId() {
+ public String getCallId() {
return mCallId;
}
@@ -161,9 +161,7 @@ public class CallMetadataSyncConnectionService extends ConnectionService {
private abstract static class CallMetadataSyncConnectionCallback {
- abstract void sendCallAction(int associationId, long callId, int action);
-
- abstract void sendStateChange(int associationId, long callId, int newState);
+ abstract void sendCallAction(int associationId, String callId, int action);
}
private static class CallMetadataSyncConnection extends Connection {
@@ -184,7 +182,7 @@ public class CallMetadataSyncConnectionService extends ConnectionService {
mCallback = callback;
}
- public long getCallId() {
+ public String getCallId() {
return mCall.getId();
}
@@ -205,22 +203,22 @@ public class CallMetadataSyncConnectionService extends ConnectionService {
}
final Bundle extras = new Bundle();
- extras.putLong(CrossDeviceCall.EXTRA_CALL_ID, mCall.getId());
+ extras.putString(CrossDeviceCall.EXTRA_CALL_ID, mCall.getId());
putExtras(extras);
int capabilities = getConnectionCapabilities();
- if (mCall.hasControl(android.companion.Telecom.Call.PUT_ON_HOLD)) {
+ if (mCall.hasControl(android.companion.Telecom.PUT_ON_HOLD)) {
capabilities |= CAPABILITY_HOLD;
} else {
capabilities &= ~CAPABILITY_HOLD;
}
- if (mCall.hasControl(android.companion.Telecom.Call.MUTE)) {
+ if (mCall.hasControl(android.companion.Telecom.MUTE)) {
capabilities |= CAPABILITY_MUTE;
} else {
capabilities &= ~CAPABILITY_MUTE;
}
mAudioManager.setMicrophoneMute(
- mCall.hasControl(android.companion.Telecom.Call.UNMUTE));
+ mCall.hasControl(android.companion.Telecom.UNMUTE));
if (capabilities != getConnectionCapabilities()) {
setConnectionCapabilities(capabilities);
}
@@ -248,8 +246,8 @@ public class CallMetadataSyncConnectionService extends ConnectionService {
int capabilities = getConnectionCapabilities();
final boolean hasHoldControl = mCall.hasControl(
- android.companion.Telecom.Call.PUT_ON_HOLD)
- || mCall.hasControl(android.companion.Telecom.Call.TAKE_OFF_HOLD);
+ android.companion.Telecom.PUT_ON_HOLD)
+ || mCall.hasControl(android.companion.Telecom.TAKE_OFF_HOLD);
if (hasHoldControl != ((getConnectionCapabilities() & CAPABILITY_HOLD)
== CAPABILITY_HOLD)) {
if (hasHoldControl) {
@@ -258,7 +256,7 @@ public class CallMetadataSyncConnectionService extends ConnectionService {
capabilities &= ~CAPABILITY_HOLD;
}
}
- final boolean hasMuteControl = mCall.hasControl(android.companion.Telecom.Call.MUTE);
+ final boolean hasMuteControl = mCall.hasControl(android.companion.Telecom.MUTE);
if (hasMuteControl != ((getConnectionCapabilities() & CAPABILITY_MUTE)
== CAPABILITY_MUTE)) {
if (hasMuteControl) {
@@ -268,7 +266,7 @@ public class CallMetadataSyncConnectionService extends ConnectionService {
}
}
mAudioManager.setMicrophoneMute(
- mCall.hasControl(android.companion.Telecom.Call.UNMUTE));
+ mCall.hasControl(android.companion.Telecom.UNMUTE));
if (capabilities != getConnectionCapabilities()) {
setConnectionCapabilities(capabilities);
}
@@ -276,12 +274,12 @@ public class CallMetadataSyncConnectionService extends ConnectionService {
@Override
public void onAnswer(int videoState) {
- sendCallAction(android.companion.Telecom.Call.ACCEPT);
+ sendCallAction(android.companion.Telecom.ACCEPT);
}
@Override
public void onReject() {
- sendCallAction(android.companion.Telecom.Call.REJECT);
+ sendCallAction(android.companion.Telecom.REJECT);
}
@Override
@@ -296,33 +294,28 @@ public class CallMetadataSyncConnectionService extends ConnectionService {
@Override
public void onSilence() {
- sendCallAction(android.companion.Telecom.Call.SILENCE);
+ sendCallAction(android.companion.Telecom.SILENCE);
}
@Override
public void onHold() {
- sendCallAction(android.companion.Telecom.Call.PUT_ON_HOLD);
+ sendCallAction(android.companion.Telecom.PUT_ON_HOLD);
}
@Override
public void onUnhold() {
- sendCallAction(android.companion.Telecom.Call.TAKE_OFF_HOLD);
+ sendCallAction(android.companion.Telecom.TAKE_OFF_HOLD);
}
@Override
public void onMuteStateChanged(boolean isMuted) {
- sendCallAction(isMuted ? android.companion.Telecom.Call.MUTE
- : android.companion.Telecom.Call.UNMUTE);
+ sendCallAction(isMuted ? android.companion.Telecom.MUTE
+ : android.companion.Telecom.UNMUTE);
}
@Override
public void onDisconnect() {
- sendCallAction(android.companion.Telecom.Call.END);
- }
-
- @Override
- public void onStateChanged(int state) {
- mCallback.sendStateChange(mAssociationId, mCall.getId(), state);
+ sendCallAction(android.companion.Telecom.END);
}
private void sendCallAction(int action) {
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
index 1e4bb9a504ba..5b0c745a7173 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
@@ -33,14 +33,14 @@ import java.util.Set;
/** A read-only snapshot of an {@link ContextSyncMessage}. */
class CallMetadataSyncData {
- final Map<Long, CallMetadataSyncData.Call> mCalls = new HashMap<>();
+ final Map<String, CallMetadataSyncData.Call> mCalls = new HashMap<>();
final List<CallMetadataSyncData.Call> mRequests = new ArrayList<>();
public void addCall(CallMetadataSyncData.Call call) {
mCalls.put(call.getId(), call);
}
- public boolean hasCall(long id) {
+ public boolean hasCall(String id) {
return mCalls.containsKey(id);
}
@@ -57,7 +57,7 @@ class CallMetadataSyncData {
}
public static class Call implements Parcelable {
- private long mId;
+ private String mId;
private String mCallerId;
private byte[] mAppIcon;
private String mAppName;
@@ -67,7 +67,7 @@ class CallMetadataSyncData {
public static Call fromParcel(Parcel parcel) {
final Call call = new Call();
- call.setId(parcel.readLong());
+ call.setId(parcel.readString());
call.setCallerId(parcel.readString());
call.setAppIcon(parcel.readBlob());
call.setAppName(parcel.readString());
@@ -82,7 +82,7 @@ class CallMetadataSyncData {
@Override
public void writeToParcel(Parcel parcel, int parcelableFlags) {
- parcel.writeLong(mId);
+ parcel.writeString(mId);
parcel.writeString(mCallerId);
parcel.writeBlob(mAppIcon);
parcel.writeString(mAppName);
@@ -94,7 +94,7 @@ class CallMetadataSyncData {
}
}
- void setId(long id) {
+ void setId(String id) {
mId = id;
}
@@ -122,7 +122,7 @@ class CallMetadataSyncData {
mControls.add(control);
}
- long getId() {
+ String getId() {
return mId;
}
@@ -157,7 +157,7 @@ class CallMetadataSyncData {
@Override
public boolean equals(Object other) {
if (other instanceof CallMetadataSyncData.Call) {
- return ((Call) other).getId() == getId();
+ return mId != null && mId.equals(((Call) other).getId());
}
return false;
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
index 443a732eb6f1..0c2373023177 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
@@ -41,7 +41,6 @@ import java.util.stream.Collectors;
public class CallMetadataSyncInCallService extends InCallService {
private static final String TAG = "CallMetadataIcs";
- private static final long NOT_VALID = -1L;
private CompanionDeviceManagerServiceInternal mCdmsi;
@@ -71,7 +70,7 @@ public class CallMetadataSyncInCallService extends InCallService {
callMetadataSyncData.getRequests().iterator();
while (iterator.hasNext()) {
final CallMetadataSyncData.Call call = iterator.next();
- if (call.getId() != 0) {
+ if (call.getId() != null) {
// The call is already assigned an id; treat as control invocations.
for (int control : call.getControls()) {
processCallControlAction(call.getId(), control);
@@ -81,41 +80,41 @@ public class CallMetadataSyncInCallService extends InCallService {
}
}
- private void processCallControlAction(long crossDeviceCallId,
+ private void processCallControlAction(String crossDeviceCallId,
int callControlAction) {
final CrossDeviceCall crossDeviceCall = getCallForId(crossDeviceCallId,
mCurrentCalls.values());
switch (callControlAction) {
- case android.companion.Telecom.Call.ACCEPT:
+ case android.companion.Telecom.ACCEPT:
if (crossDeviceCall != null) {
crossDeviceCall.doAccept();
}
break;
- case android.companion.Telecom.Call.REJECT:
+ case android.companion.Telecom.REJECT:
if (crossDeviceCall != null) {
crossDeviceCall.doReject();
}
break;
- case android.companion.Telecom.Call.SILENCE:
+ case android.companion.Telecom.SILENCE:
doSilence();
break;
- case android.companion.Telecom.Call.MUTE:
+ case android.companion.Telecom.MUTE:
doMute();
break;
- case android.companion.Telecom.Call.UNMUTE:
+ case android.companion.Telecom.UNMUTE:
doUnmute();
break;
- case android.companion.Telecom.Call.END:
+ case android.companion.Telecom.END:
if (crossDeviceCall != null) {
crossDeviceCall.doEnd();
}
break;
- case android.companion.Telecom.Call.PUT_ON_HOLD:
+ case android.companion.Telecom.PUT_ON_HOLD:
if (crossDeviceCall != null) {
crossDeviceCall.doPutOnHold();
}
break;
- case android.companion.Telecom.Call.TAKE_OFF_HOLD:
+ case android.companion.Telecom.TAKE_OFF_HOLD:
if (crossDeviceCall != null) {
crossDeviceCall.doTakeOffHold();
}
@@ -171,12 +170,12 @@ public class CallMetadataSyncInCallService extends InCallService {
@Nullable
@VisibleForTesting
- CrossDeviceCall getCallForId(long crossDeviceCallId, Collection<CrossDeviceCall> calls) {
- if (crossDeviceCallId == NOT_VALID) {
+ CrossDeviceCall getCallForId(String crossDeviceCallId, Collection<CrossDeviceCall> calls) {
+ if (crossDeviceCallId == null) {
return null;
}
for (CrossDeviceCall crossDeviceCall : calls) {
- if (crossDeviceCall.getId() == crossDeviceCallId) {
+ if (crossDeviceCallId.equals(crossDeviceCall.getId())) {
return crossDeviceCall;
}
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
index ac981d45561b..168068ec6497 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
@@ -23,7 +23,6 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Bundle;
import android.telecom.Call;
import android.telecom.CallAudioState;
import android.telecom.VideoProfile;
@@ -34,7 +33,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.ByteArrayOutputStream;
import java.util.HashSet;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.UUID;
/** Data holder for a telecom call and additional metadata. */
public class CrossDeviceCall {
@@ -45,9 +44,7 @@ public class CrossDeviceCall {
"com.android.companion.datatransfer.contextsync.extra.CALL_ID";
private static final int APP_ICON_BITMAP_DIMENSION = 256;
- private static final AtomicLong sNextId = new AtomicLong(1);
-
- private final long mId;
+ private final String mId;
private Call mCall;
@VisibleForTesting boolean mIsEnterprise;
@VisibleForTesting boolean mIsOtt;
@@ -64,14 +61,14 @@ public class CrossDeviceCall {
CallAudioState callAudioState) {
this(packageManager, call.getDetails(), callAudioState);
mCall = call;
- final Bundle extras = new Bundle();
- extras.putLong(EXTRA_CALL_ID, mId);
- call.putExtras(extras);
+ call.putExtra(EXTRA_CALL_ID, mId);
}
CrossDeviceCall(PackageManager packageManager, Call.Details callDetails,
CallAudioState callAudioState) {
- mId = sNextId.getAndIncrement();
+ final String predefinedId = callDetails.getIntentExtras() != null
+ ? callDetails.getIntentExtras().getString(EXTRA_CALL_ID) : null;
+ mId = predefinedId != null ? predefinedId : UUID.randomUUID().toString();
mCallingAppPackageName =
callDetails.getAccountHandle().getComponentName().getPackageName();
mIsOtt = (callDetails.getCallCapabilities() & Call.Details.PROPERTY_SELF_MANAGED)
@@ -145,7 +142,7 @@ public class CrossDeviceCall {
if (mStatus == android.companion.Telecom.Call.RINGING) {
mStatus = android.companion.Telecom.Call.RINGING_SILENCED;
}
- mControls.remove(android.companion.Telecom.Call.SILENCE);
+ mControls.remove(android.companion.Telecom.SILENCE);
}
@VisibleForTesting
@@ -156,26 +153,26 @@ public class CrossDeviceCall {
mControls.clear();
if (mStatus == android.companion.Telecom.Call.RINGING
|| mStatus == android.companion.Telecom.Call.RINGING_SILENCED) {
- mControls.add(android.companion.Telecom.Call.ACCEPT);
- mControls.add(android.companion.Telecom.Call.REJECT);
+ mControls.add(android.companion.Telecom.ACCEPT);
+ mControls.add(android.companion.Telecom.REJECT);
if (mStatus == android.companion.Telecom.Call.RINGING) {
- mControls.add(android.companion.Telecom.Call.SILENCE);
+ mControls.add(android.companion.Telecom.SILENCE);
}
}
if (mStatus == android.companion.Telecom.Call.ONGOING
|| mStatus == android.companion.Telecom.Call.ON_HOLD) {
- mControls.add(android.companion.Telecom.Call.END);
+ mControls.add(android.companion.Telecom.END);
if (callDetails.can(Call.Details.CAPABILITY_HOLD)) {
mControls.add(
mStatus == android.companion.Telecom.Call.ON_HOLD
- ? android.companion.Telecom.Call.TAKE_OFF_HOLD
- : android.companion.Telecom.Call.PUT_ON_HOLD);
+ ? android.companion.Telecom.TAKE_OFF_HOLD
+ : android.companion.Telecom.PUT_ON_HOLD);
}
}
if (mStatus == android.companion.Telecom.Call.ONGOING && callDetails.can(
Call.Details.CAPABILITY_MUTE)) {
- mControls.add(mIsMuted ? android.companion.Telecom.Call.UNMUTE
- : android.companion.Telecom.Call.MUTE);
+ mControls.add(mIsMuted ? android.companion.Telecom.UNMUTE
+ : android.companion.Telecom.MUTE);
}
}
@@ -212,7 +209,7 @@ public class CrossDeviceCall {
}
}
- public long getId() {
+ public String getId() {
return mId;
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
index adc5faf24f2c..e5ab963b6cbb 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
@@ -270,7 +270,7 @@ public class CrossDeviceSyncController {
while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pis.getFieldNumber()) {
case (int) Telecom.Call.ID:
- call.setId(pis.readLong(Telecom.Call.ID));
+ call.setId(pis.readString(Telecom.Call.ID));
break;
case (int) Telecom.Call.ORIGIN:
final long originToken = pis.start(Telecom.Call.ORIGIN);
@@ -336,7 +336,7 @@ public class CrossDeviceSyncController {
}
/** Create a call control message. */
- public static byte[] createCallControlMessage(long callId, int control) {
+ public static byte[] createCallControlMessage(String callId, int control) {
final ProtoOutputStream pos = new ProtoOutputStream();
pos.write(ContextSyncMessage.VERSION, CURRENT_VERSION);
final long telecomToken = pos.start(ContextSyncMessage.TELECOM);
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index f6b99b551ecb..a5410e448c7b 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -27,17 +27,24 @@ import android.companion.AssociationInfo;
import android.net.MacAddress;
import android.os.Handler;
import android.os.HandlerExecutor;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.companion.AssociationStore;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
@SuppressLint("LongLogTag")
-class BluetoothCompanionDeviceConnectionListener
+public class BluetoothCompanionDeviceConnectionListener
extends BluetoothAdapter.BluetoothConnectionCallback
implements AssociationStore.OnChangeListener {
private static final String TAG = "CDM_BluetoothCompanionDeviceConnectionListener";
@@ -48,15 +55,25 @@ class BluetoothCompanionDeviceConnectionListener
void onBluetoothCompanionDeviceDisconnected(int associationId);
}
+ private final UserManager mUserManager;
private final @NonNull AssociationStore mAssociationStore;
private final @NonNull Callback mCallback;
/** A set of ALL connected BT device (not only companion.) */
private final @NonNull Map<MacAddress, BluetoothDevice> mAllConnectedDevices = new HashMap<>();
- BluetoothCompanionDeviceConnectionListener(@NonNull AssociationStore associationStore,
- @NonNull Callback callback) {
+ /**
+ * A structure hold the connected BT devices that are pending to be reported to the companion
+ * app when the user unlocks the local device per userId.
+ */
+ @GuardedBy("mPendingConnectedDevices")
+ @NonNull
+ final SparseArray<Set<BluetoothDevice>> mPendingConnectedDevices = new SparseArray<>();
+
+ BluetoothCompanionDeviceConnectionListener(UserManager userManager,
+ @NonNull AssociationStore associationStore, @NonNull Callback callback) {
mAssociationStore = associationStore;
mCallback = callback;
+ mUserManager = userManager;
}
public void init(@NonNull BluetoothAdapter btAdapter) {
@@ -76,12 +93,26 @@ class BluetoothCompanionDeviceConnectionListener
if (DEBUG) Log.i(TAG, "onDevice_Connected() " + btDeviceToString(device));
final MacAddress macAddress = MacAddress.fromString(device.getAddress());
+ final int userId = UserHandle.myUserId();
+
if (mAllConnectedDevices.put(macAddress, device) != null) {
if (DEBUG) Log.w(TAG, "Device " + btDeviceToString(device) + " is already connected.");
return;
}
+ // Try to bind and notify the app after the phone is unlocked.
+ if (!mUserManager.isUserUnlockingOrUnlocked(UserHandle.myUserId())) {
+ Slog.i(TAG, "Current user is not in unlocking or unlocked stage yet. Notify "
+ + "the application when the phone is unlocked");
+ synchronized (mPendingConnectedDevices) {
+ Set<BluetoothDevice> bluetoothDevices = mPendingConnectedDevices.get(
+ userId, new HashSet<>());
+ bluetoothDevices.add(device);
+ mPendingConnectedDevices.put(userId, bluetoothDevices);
+ }
- onDeviceConnectivityChanged(device, true);
+ } else {
+ onDeviceConnectivityChanged(device, true);
+ }
}
/**
@@ -98,6 +129,8 @@ class BluetoothCompanionDeviceConnectionListener
}
final MacAddress macAddress = MacAddress.fromString(device.getAddress());
+ final int userId = UserHandle.myUserId();
+
if (mAllConnectedDevices.remove(macAddress) == null) {
if (DEBUG) {
Log.w(TAG, "The device wasn't tracked as connected " + btDeviceToString(device));
@@ -105,6 +138,19 @@ class BluetoothCompanionDeviceConnectionListener
return;
}
+ // Do not need to report the connectivity since the user is not unlock the phone so
+ // that cdm is not bind with the app yet.
+ if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
+ synchronized (mPendingConnectedDevices) {
+ Set<BluetoothDevice> bluetoothDevices = mPendingConnectedDevices.get(userId);
+ if (bluetoothDevices != null) {
+ bluetoothDevices.remove(device);
+ }
+ }
+
+ return;
+ }
+
onDeviceConnectivityChanged(device, false);
}
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index 4010be922b2c..f6e9415a2a7e 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -23,13 +23,16 @@ import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.companion.AssociationInfo;
import android.content.Context;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserManager;
import android.util.Log;
+import android.util.SparseArray;
import com.android.server.companion.AssociationStore;
@@ -86,13 +89,12 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
private final SimulatedDevicePresenceSchedulerHelper mSchedulerHelper =
new SimulatedDevicePresenceSchedulerHelper();
- public CompanionDevicePresenceMonitor(@NonNull AssociationStore associationStore,
- @NonNull Callback callback) {
+ public CompanionDevicePresenceMonitor(UserManager userManager,
+ @NonNull AssociationStore associationStore, @NonNull Callback callback) {
mAssociationStore = associationStore;
mCallback = callback;
-
- mBtConnectionListener = new BluetoothCompanionDeviceConnectionListener(associationStore,
- /* BluetoothCompanionDeviceConnectionListener.Callback */ this);
+ mBtConnectionListener = new BluetoothCompanionDeviceConnectionListener(userManager,
+ associationStore, /* BluetoothCompanionDeviceConnectionListener.Callback */ this);
mBleScanner = new BleCompanionDeviceScanner(associationStore,
/* BleCompanionDeviceScanner.Callback */ this);
}
@@ -298,6 +300,15 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
// what's needed.
}
+ /**
+ * Return a set of devices that pending to report connectivity
+ */
+ public SparseArray<Set<BluetoothDevice>> getPendingConnectedDevices() {
+ synchronized (mBtConnectionListener.mPendingConnectedDevices) {
+ return mBtConnectionListener.mPendingConnectedDevices;
+ }
+ }
+
private static void enforceCallerShellOrRoot() {
final int callingUid = Binder.getCallingUid();
if (callingUid == SHELL_UID || callingUid == ROOT_UID) return;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index cf09fde9ec2c..ca50af8075c6 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -52,6 +52,7 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVI
import static android.os.PowerExemptionManager.REASON_ACTIVE_DEVICE_ADMIN;
import static android.os.PowerExemptionManager.REASON_ACTIVITY_STARTER;
import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD;
+import static android.os.PowerExemptionManager.REASON_ALARM_MANAGER_ALARM_CLOCK;
import static android.os.PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE;
import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_BACKGROUND_FGS_PERMISSION;
@@ -458,11 +459,12 @@ public final class ActiveServices {
public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
boolean restricted) {
synchronized (mAm) {
- if (!isForegroundServiceAllowedInBackgroundRestricted(uid, packageName)) {
- stopAllForegroundServicesLocked(uid, packageName);
- }
mAm.mProcessList.updateBackgroundRestrictedForUidPackageLocked(
uid, packageName, restricted);
+ if (!isForegroundServiceAllowedInBackgroundRestricted(uid, packageName)
+ && !isTempAllowedByAlarmClock(uid)) {
+ stopAllForegroundServicesLocked(uid, packageName);
+ }
}
}
}
@@ -475,7 +477,11 @@ public final class ActiveServices {
final ServiceRecord r = smap.mServicesByInstanceName.valueAt(i);
if (uid == r.serviceInfo.applicationInfo.uid
|| packageName.equals(r.serviceInfo.packageName)) {
- if (r.isForeground) {
+ // If the FGS is started by temp allowlist of alarm-clock
+ // (REASON_ALARM_MANAGER_ALARM_CLOCK), allow it to continue and do not stop it,
+ // even the app is background-restricted.
+ if (r.isForeground
+ && r.mAllowStartForegroundAtEntering != REASON_ALARM_MANAGER_ALARM_CLOCK) {
toStop.add(r);
}
}
@@ -872,7 +878,9 @@ public final class ActiveServices {
// start analogously to the legacy-app forced-restrictions case, regardless
// of its target SDK version.
boolean forcedStandby = false;
- if (bgLaunch && appRestrictedAnyInBackground(appUid, appPackageName)) {
+ if (bgLaunch
+ && appRestrictedAnyInBackground(appUid, appPackageName)
+ && !isTempAllowedByAlarmClock(appUid)) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG, "Forcing bg-only service start only for " + r.shortInstanceName
+ " : bgLaunch=" + bgLaunch + " callerFg=" + callerFg);
@@ -1931,6 +1939,20 @@ public final class ActiveServices {
&& isForegroundServiceAllowedInBackgroundRestricted(app);
}
+ /*
+ * If the FGS start is temp allowlisted by alarm-clock(REASON_ALARM_MANAGER_ALARM_CLOCK), it is
+ * allowed even the app is background-restricted.
+ */
+ private boolean isTempAllowedByAlarmClock(int uid) {
+ final ActivityManagerService.FgsTempAllowListItem item =
+ mAm.isAllowlistedForFgsStartLOSP(uid);
+ if (item != null) {
+ return item.mReasonCode == REASON_ALARM_MANAGER_ALARM_CLOCK;
+ } else {
+ return false;
+ }
+ }
+
void logFgsApiBeginLocked(int uid, int pid, int apiType) {
synchronized (mFGSLogger) {
mFGSLogger.logForegroundServiceApiEventBegin(uid, pid, apiType, "");
@@ -2064,7 +2086,8 @@ public final class ActiveServices {
// Apps that are TOP or effectively similar may call startForeground() on
// their services even if they are restricted from doing that while in bg.
if (!ignoreForeground
- && !isForegroundServiceAllowedInBackgroundRestricted(r.app)) {
+ && !isForegroundServiceAllowedInBackgroundRestricted(r.app)
+ && !isTempAllowedByAlarmClock(r.app.uid)) {
Slog.w(TAG,
"Service.startForeground() not allowed due to bg restriction: service "
+ r.shortInstanceName);
@@ -8217,7 +8240,11 @@ public final class ActiveServices {
: ForegroundServiceDelegationOptions.DELEGATION_SERVICE_DEFAULT,
0 /* api_sate */,
null /* api_type */,
- null /* api_timestamp */);
+ null /* api_timestamp */,
+ mAm.getUidStateLocked(r.appInfo.uid),
+ mAm.getUidProcessCapabilityLocked(r.appInfo.uid),
+ mAm.getUidStateLocked(r.mRecentCallingUid),
+ mAm.getUidProcessCapabilityLocked(r.mRecentCallingUid));
int event = 0;
if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ea8745dc666d..a992765c0411 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5190,7 +5190,10 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new IllegalArgumentException(
"Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
}
- if (PendingIntent.isNewMutableDisallowedImplicitPendingIntent(flags, intent)) {
+ boolean isActivityResultType =
+ type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT;
+ if (PendingIntent.isNewMutableDisallowedImplicitPendingIntent(flags, intent,
+ isActivityResultType)) {
boolean isChangeEnabled = CompatChanges.isChangeEnabled(
PendingIntent.BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT,
owningUid);
@@ -16057,6 +16060,8 @@ public class ActivityManagerService extends IActivityManager.Stub
final int procState = uidRec != null
? uidRec.getSetProcState() : PROCESS_STATE_NONEXISTENT;
+ final int procAdj = uidRec != null
+ ? uidRec.getMinProcAdj() : ProcessList.INVALID_ADJ;
final long procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0;
final int capability = uidRec != null ? uidRec.getSetCapability() : 0;
final boolean ephemeral = uidRec != null ? uidRec.isEphemeral() : isEphemeralLocked(uid);
@@ -16072,7 +16077,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final int enqueuedChange = mUidObserverController.enqueueUidChange(
uidRec == null ? null : uidRec.pendingChange,
- uid, change, procState, procStateSeq, capability, ephemeral);
+ uid, change, procState, procAdj, procStateSeq, capability, ephemeral);
if (uidRec != null) {
uidRec.setLastReportedChange(enqueuedChange);
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index 5a4d315767ca..4a69f90d9fc0 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -67,7 +67,6 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
-import android.os.UserManager;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
@@ -78,6 +77,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
+import com.android.server.pm.UserJourneyLogger;
import com.android.server.pm.UserManagerInternal;
import dalvik.annotation.optimization.NeverCompile;
@@ -1518,7 +1518,7 @@ public class BroadcastQueueImpl extends BroadcastQueue {
final UserInfo userInfo =
(umInternal != null) ? umInternal.getUserInfo(r.userId) : null;
if (userInfo != null) {
- userType = UserManager.getUserTypeForStatsd(userInfo.userType);
+ userType = UserJourneyLogger.getUserTypeForStatsd(userInfo.userType);
}
Slog.i(TAG_BROADCAST,
"BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED action:"
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 1426cfd65286..3e82d557c01a 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1015,6 +1015,12 @@ public final class CachedAppOptimizer {
private static native String getFreezerCheckPath();
/**
+ * Check if task_profiles.json includes valid freezer profiles and actions
+ * @return false if there are invalid profiles or actions
+ */
+ private static native boolean isFreezerProfileValid();
+
+ /**
* Determines whether the freezer is supported by this system
*/
public static boolean isFreezerSupported() {
@@ -1031,16 +1037,19 @@ public final class CachedAppOptimizer {
// Also check freezer binder ioctl
Slog.d(TAG_AM, "Checking binder freezer ioctl");
getBinderFreezeInfo(Process.myPid());
- supported = true;
+
+ // Check if task_profiles.json contains invalid profiles
+ Slog.d(TAG_AM, "Checking freezer profiles");
+ supported = isFreezerProfileValid();
} else {
- Slog.e(TAG_AM, "unexpected value in cgroup.freeze");
+ Slog.e(TAG_AM, "Unexpected value in cgroup.freeze");
}
} catch (java.io.FileNotFoundException e) {
- Slog.w(TAG_AM, "cgroup.freeze not present");
+ Slog.w(TAG_AM, "File cgroup.freeze not present");
} catch (RuntimeException e) {
- Slog.w(TAG_AM, "unable to read freezer info");
+ Slog.w(TAG_AM, "Unable to read freezer info");
} catch (Exception e) {
- Slog.w(TAG_AM, "unable to read cgroup.freeze: " + e.toString());
+ Slog.w(TAG_AM, "Unable to read cgroup.freeze: " + e.toString());
}
if (fr != null) {
@@ -2100,9 +2109,12 @@ public final class CachedAppOptimizer {
final boolean frozen;
final ProcessCachedOptimizerRecord opt = proc.mOptRecord;
- opt.setPendingFreeze(false);
-
synchronized (mProcLock) {
+ // someone has canceled this freeze
+ if (!opt.isPendingFreeze()) {
+ return;
+ }
+ opt.setPendingFreeze(false);
pid = proc.getPid();
if (mFreezerOverride) {
@@ -2148,7 +2160,6 @@ public final class CachedAppOptimizer {
try {
traceAppFreeze(proc.processName, pid, -1);
Process.setProcessFrozen(pid, proc.uid, true);
-
opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis());
opt.setFrozen(true);
opt.setHasCollectedFrozenPSS(false);
diff --git a/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java b/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java
index 8f84b08ff6a6..79089074dd1c 100644
--- a/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java
+++ b/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java
@@ -28,12 +28,13 @@ import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_USB;
import static android.os.Process.INVALID_UID;
import android.annotation.IntDef;
+import android.app.ActivityManager;
import android.app.ActivityManager.ForegroundServiceApiType;
import android.app.ForegroundServiceDelegationOptions;
import android.content.ComponentName;
import android.content.pm.ServiceInfo;
import android.util.ArrayMap;
-import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -191,13 +192,20 @@ public class ForegroundServiceTypeLoggerModule {
final ArrayList<Integer> apiTypes = convertFgsTypeToApiTypes(record.foregroundServiceType);
final UidState uidState = mUids.get(uid);
if (uidState == null) {
- Log.e(TAG, "FGS stop call being logged with no start call for UID " + uid);
+ Slog.wtfStack(TAG, "FGS stop call being logged with no start call for UID for UID "
+ + uid
+ + " in package " + record.packageName);
return;
}
final ArrayList<Integer> apisFound = new ArrayList<>();
final ArrayList<Long> timestampsFound = new ArrayList<>();
for (int i = 0, size = apiTypes.size(); i < size; i++) {
- int apiType = apiTypes.get(i);
+ final int apiType = apiTypes.get(i);
+ if (!uidState.mOpenWithFgsCount.contains(apiType)) {
+ Slog.wtfStack(TAG, "Logger should be tracking FGS types correctly for UID " + uid
+ + " in package " + record.packageName);
+ continue;
+ }
// retrieve the eligible closed call
// we only want to log if this is the only
// open in flight call. If there are other calls,
@@ -214,7 +222,8 @@ public class ForegroundServiceTypeLoggerModule {
final ArrayMap<ComponentName, ServiceRecord> runningFgsOfType =
uidState.mRunningFgs.get(apiType);
if (runningFgsOfType == null) {
- Log.w(TAG, "Could not find appropriate running FGS for FGS stop");
+ Slog.w(TAG, "Could not find appropriate running FGS for FGS stop for UID " + uid
+ + " in package " + record.packageName);
continue;
}
@@ -321,7 +330,7 @@ public class ForegroundServiceTypeLoggerModule {
// it's not related to any FGS
UidState uidState = mUids.get(uid);
if (uidState == null) {
- Log.w(TAG, "API event end called before start!");
+ Slog.w(TAG, "API event end called before start!");
return -1;
}
if (uidState.mOpenWithFgsCount.contains(apiType)) {
@@ -466,7 +475,11 @@ public class ForegroundServiceTypeLoggerModule {
: ForegroundServiceDelegationOptions.DELEGATION_SERVICE_DEFAULT,
apiState,
apiType,
- timestamp);
+ timestamp,
+ ActivityManager.PROCESS_STATE_UNKNOWN,
+ ActivityManager.PROCESS_CAPABILITY_NONE,
+ ActivityManager.PROCESS_STATE_UNKNOWN,
+ ActivityManager.PROCESS_CAPABILITY_NONE);
}
/**
@@ -500,7 +513,11 @@ public class ForegroundServiceTypeLoggerModule {
0,
apiState,
apiType,
- timestamp);
+ timestamp,
+ ActivityManager.PROCESS_STATE_UNKNOWN,
+ ActivityManager.PROCESS_CAPABILITY_NONE,
+ ActivityManager.PROCESS_STATE_UNKNOWN,
+ ActivityManager.PROCESS_CAPABILITY_NONE);
}
/**
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 438a08c44ef4..0417b8cfa2e2 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -644,6 +644,11 @@ class ProcessRecord implements WindowProcessListener {
}
}
+ @GuardedBy({"mService", "mProcLock"})
+ int getSetAdj() {
+ return mState.getSetAdj();
+ }
+
@GuardedBy(anyOf = {"mService", "mProcLock"})
IApplicationThread getThread() {
return mThread;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 78aafeba3b22..6551db9ad783 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -643,6 +643,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
pw.print(prefix); pw.print("lastUntrustedSetFgsRestrictionAllowedTime=");
TimeUtils.formatDuration(mLastUntrustedSetFgsRestrictionAllowedTime, now, pw);
+ pw.println();
if (delayed) {
pw.print(prefix); pw.print("delayed="); pw.println(delayed);
diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java
index 51cb9878c0b3..790cc7b87f80 100644
--- a/services/core/java/com/android/server/am/UidObserverController.java
+++ b/services/core/java/com/android/server/am/UidObserverController.java
@@ -96,7 +96,7 @@ public class UidObserverController {
}
int enqueueUidChange(@Nullable ChangeRecord currentRecord, int uid, int change, int procState,
- long procStateSeq, int capability, boolean ephemeral) {
+ int procAdj, long procStateSeq, int capability, boolean ephemeral) {
synchronized (mLock) {
if (mPendingUidChanges.size() == 0) {
if (DEBUG_UID_OBSERVERS) {
@@ -117,6 +117,7 @@ public class UidObserverController {
changeRecord.uid = uid;
changeRecord.change = change;
changeRecord.procState = procState;
+ changeRecord.procAdj = procAdj;
changeRecord.procStateSeq = procStateSeq;
changeRecord.capability = capability;
changeRecord.ephemeral = ephemeral;
@@ -344,7 +345,7 @@ public class UidObserverController {
}
if ((reg.mWhich & ActivityManager.UID_OBSERVER_PROC_OOM_ADJ) != 0
&& (change & UidRecord.CHANGE_PROCADJ) != 0) {
- observer.onUidProcAdjChanged(item.uid);
+ observer.onUidProcAdjChanged(item.uid, item.procAdj);
}
}
final int duration = (int) (SystemClock.uptimeMillis() - start);
@@ -426,6 +427,7 @@ public class UidObserverController {
public int uid;
public int change;
public int procState;
+ public int procAdj;
public int capability;
public boolean ephemeral;
public long procStateSeq;
@@ -435,6 +437,7 @@ public class UidObserverController {
changeRecord.uid = uid;
changeRecord.change = change;
changeRecord.procState = procState;
+ changeRecord.procAdj = procAdj;
changeRecord.capability = capability;
changeRecord.ephemeral = ephemeral;
changeRecord.procStateSeq = procStateSeq;
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index e39ac2b08479..993088ef106e 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -51,6 +51,12 @@ public final class UidRecord {
private boolean mProcAdjChanged;
@CompositeRWLock({"mService", "mProcLock"})
+ private int mCurAdj;
+
+ @CompositeRWLock({"mService", "mProcLock"})
+ private int mSetAdj;
+
+ @CompositeRWLock({"mService", "mProcLock"})
private int mCurCapability;
@CompositeRWLock({"mService", "mProcLock"})
@@ -201,12 +207,24 @@ public final class UidRecord {
mProcAdjChanged = false;
}
- @GuardedBy({"mService", "mProcLock"})
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
boolean getProcAdjChanged() {
return mProcAdjChanged;
}
@GuardedBy(anyOf = {"mService", "mProcLock"})
+ int getMinProcAdj() {
+ int minAdj = ProcessList.UNKNOWN_ADJ;
+ for (int i = mProcRecords.size() - 1; i >= 0; i--) {
+ int adj = mProcRecords.valueAt(i).getSetAdj();
+ if (adj < minAdj) {
+ minAdj = adj;
+ }
+ }
+ return minAdj;
+ }
+
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
int getCurCapability() {
return mCurCapability;
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b2fdee7a6f89..06af2ce9d655 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -46,13 +46,24 @@ import static com.android.server.am.UserState.STATE_BOOTING;
import static com.android.server.am.UserState.STATE_RUNNING_LOCKED;
import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKED;
import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKING;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_ABORTED;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_INVALID_SESSION_ID;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_BEGIN;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_FINISH;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_NONE;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_START;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_STOP;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_SWITCH_FG;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_SWITCH_UI;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_UNLOCKED_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_UNLOCKING_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED;
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
import static com.android.server.pm.UserManagerInternal.USER_START_MODE_BACKGROUND_VISIBLE;
import static com.android.server.pm.UserManagerInternal.USER_START_MODE_FOREGROUND;
import static com.android.server.pm.UserManagerInternal.userAssignmentResultToString;
import static com.android.server.pm.UserManagerInternal.userStartModeToString;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -123,6 +134,8 @@ import com.android.server.LocalServices;
import com.android.server.SystemService.UserCompletedEventType;
import com.android.server.SystemServiceManager;
import com.android.server.am.UserState.KeyEvictedCallback;
+import com.android.server.pm.UserJourneyLogger;
+import com.android.server.pm.UserJourneyLogger.UserJourneySession;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
import com.android.server.pm.UserManagerInternal.UserStartMode;
@@ -138,7 +151,6 @@ import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -221,75 +233,6 @@ class UserController implements Handler.Callback {
// TODO(b/197344658): Increase to 10s or 15s once we have a switch-UX-is-done invocation too.
private static final int USER_COMPLETED_EVENT_DELAY_MS = 5 * 1000;
- // Used for statsd logging with UserLifecycleJourneyReported + UserLifecycleEventOccurred atoms
- private static final long INVALID_SESSION_ID = 0;
-
- // The various user journeys, defined in the UserLifecycleJourneyReported atom for statsd
- private static final int USER_JOURNEY_UNKNOWN =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__UNKNOWN;
- private static final int USER_JOURNEY_USER_SWITCH_FG =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_SWITCH_FG;
- private static final int USER_JOURNEY_USER_SWITCH_UI =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_SWITCH_UI;
- private static final int USER_JOURNEY_USER_START =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_START;
- private static final int USER_JOURNEY_USER_CREATE =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE;
- private static final int USER_JOURNEY_USER_STOP =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_STOP;
- @IntDef(prefix = { "USER_JOURNEY" }, value = {
- USER_JOURNEY_UNKNOWN,
- USER_JOURNEY_USER_SWITCH_FG,
- USER_JOURNEY_USER_SWITCH_UI,
- USER_JOURNEY_USER_START,
- USER_JOURNEY_USER_CREATE,
- USER_JOURNEY_USER_STOP
- })
- @interface UserJourney {}
-
- // The various user lifecycle events, defined in the UserLifecycleEventOccurred atom for statsd
- private static final int USER_LIFECYCLE_EVENT_UNKNOWN =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNKNOWN;
- private static final int USER_LIFECYCLE_EVENT_SWITCH_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__SWITCH_USER;
- private static final int USER_LIFECYCLE_EVENT_START_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__START_USER;
- private static final int USER_LIFECYCLE_EVENT_CREATE_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER;
- private static final int USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__USER_RUNNING_LOCKED;
- private static final int USER_LIFECYCLE_EVENT_UNLOCKING_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNLOCKING_USER;
- private static final int USER_LIFECYCLE_EVENT_UNLOCKED_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNLOCKED_USER;
- private static final int USER_LIFECYCLE_EVENT_STOP_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__STOP_USER;
- @IntDef(prefix = { "USER_LIFECYCLE_EVENT" }, value = {
- USER_LIFECYCLE_EVENT_UNKNOWN,
- USER_LIFECYCLE_EVENT_SWITCH_USER,
- USER_LIFECYCLE_EVENT_START_USER,
- USER_LIFECYCLE_EVENT_CREATE_USER,
- USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
- USER_LIFECYCLE_EVENT_UNLOCKING_USER,
- USER_LIFECYCLE_EVENT_UNLOCKED_USER,
- USER_LIFECYCLE_EVENT_STOP_USER
- })
- @interface UserLifecycleEvent {}
-
- // User lifecyle event state, defined in the UserLifecycleEventOccurred atom for statsd
- private static final int USER_LIFECYCLE_EVENT_STATE_BEGIN =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__BEGIN;
- private static final int USER_LIFECYCLE_EVENT_STATE_FINISH =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__FINISH;
- private static final int USER_LIFECYCLE_EVENT_STATE_NONE =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__NONE;
- @IntDef(prefix = { "USER_LIFECYCLE_EVENT_STATE" }, value = {
- USER_LIFECYCLE_EVENT_STATE_BEGIN,
- USER_LIFECYCLE_EVENT_STATE_FINISH,
- USER_LIFECYCLE_EVENT_STATE_NONE,
- })
- @interface UserLifecycleEventState {}
-
/**
* Maximum number of users we allow to be running at a time, including system user.
*
@@ -420,13 +363,6 @@ class UserController implements Handler.Callback {
private final ArrayList<Integer> mLastActiveUsers = new ArrayList<>();
/**
- * {@link UserIdInt} to {@link UserJourneySession} mapping used for statsd logging for the
- * UserLifecycleJourneyReported and UserLifecycleEventOccurred atoms.
- */
- @GuardedBy("mUserIdToUserJourneyMap")
- private final SparseArray<UserJourneySession> mUserIdToUserJourneyMap = new SparseArray<>();
-
- /**
* Map of userId to {@link UserCompletedEventType} event flags, indicating which as-yet-
* unreported user-starting events have transpired for the given user.
*/
@@ -621,8 +557,9 @@ class UserController implements Handler.Callback {
// but we might immediately step into RUNNING below if the user
// storage is already unlocked.
if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) {
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
- USER_LIFECYCLE_EVENT_STATE_NONE);
+ mInjector.getUserJourneyLogger()
+ .logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
+ EVENT_STATE_NONE);
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
// Do not report secondary users, runtime restarts or first boot/upgrade
if (userId == UserHandle.USER_SYSTEM
@@ -694,8 +631,9 @@ class UserController implements Handler.Callback {
private boolean finishUserUnlocking(final UserState uss) {
final int userId = uss.mHandle.getIdentifier();
EventLog.writeEvent(EventLogTags.UC_FINISH_USER_UNLOCKING, userId);
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_UNLOCKING_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+ mInjector.getUserJourneyLogger()
+ .logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_UNLOCKING_USER,
+ EVENT_STATE_BEGIN);
// If the user key hasn't been unlocked yet, we cannot proceed.
if (!StorageManager.isUserKeyUnlocked(userId)) return false;
synchronized (mLock) {
@@ -1073,9 +1011,7 @@ class UserController implements Handler.Callback {
return;
}
- logUserJourneyInfo(null, getUserInfo(userId), USER_JOURNEY_USER_STOP);
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+ logUserJourneyBegin(userId, USER_JOURNEY_USER_STOP);
if (stopUserCallback != null) {
uss.mStopCallbacks.add(stopUserCallback);
@@ -1138,9 +1074,16 @@ class UserController implements Handler.Callback {
synchronized (mLock) {
if (uss.state != UserState.STATE_STOPPING) {
// Whoops, we are being started back up. Abort, abort!
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER,
- USER_LIFECYCLE_EVENT_STATE_NONE);
- clearSessionId(userId);
+ UserJourneySession session = mInjector.getUserJourneyLogger()
+ .logUserJourneyFinishWithError(-1, getUserInfo(userId),
+ USER_JOURNEY_USER_STOP, ERROR_CODE_ABORTED);
+ if (session != null) {
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, session);
+ } else {
+ mInjector.getUserJourneyLogger()
+ .logUserJourneyFinishWithError(-1, getUserInfo(userId),
+ USER_JOURNEY_USER_STOP, ERROR_CODE_INVALID_SESSION_ID);
+ }
return;
}
uss.setState(UserState.STATE_SHUTDOWN);
@@ -1247,9 +1190,11 @@ class UserController implements Handler.Callback {
mInjector.getUserManager().removeUserEvenWhenDisallowed(userId);
}
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER,
- USER_LIFECYCLE_EVENT_STATE_FINISH);
- clearSessionId(userId);
+ UserJourneySession session = mInjector.getUserJourneyLogger()
+ .logUserJourneyFinish(-1, userInfo, USER_JOURNEY_USER_STOP);
+ if (session != null) {
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, session);
+ }
if (lockUser) {
dispatchUserLocking(userIdToLock, keyEvictedCallbacks);
@@ -1259,9 +1204,11 @@ class UserController implements Handler.Callback {
// which was paused while the SHUTDOWN flow of the user was in progress.
resumePendingUserStarts(userId);
} else {
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER,
- USER_LIFECYCLE_EVENT_STATE_NONE);
- clearSessionId(userId);
+ UserJourneySession session = mInjector.getUserJourneyLogger()
+ .finishAndClearIncompleteUserJourney(userId, USER_JOURNEY_USER_STOP);
+ if (session != null) {
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, session);
+ }
}
}
@@ -3135,10 +3082,7 @@ class UserController implements Handler.Callback {
public boolean handleMessage(Message msg) {
switch (msg.what) {
case START_USER_SWITCH_FG_MSG:
- logUserJourneyInfo(getUserInfo(getCurrentUserId()), getUserInfo(msg.arg1),
- USER_JOURNEY_USER_SWITCH_FG);
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_SWITCH_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+ logUserJourneyBegin(msg.arg1, USER_JOURNEY_USER_SWITCH_FG);
startUserInForeground(msg.arg1);
break;
case REPORT_USER_SWITCH_MSG:
@@ -3160,18 +3104,15 @@ class UserController implements Handler.Callback {
mInjector.batteryStatsServiceNoteEvent(
BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
Integer.toString(msg.arg1), msg.arg1);
- logUserJourneyInfo(null, getUserInfo(msg.arg1), USER_JOURNEY_USER_START);
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_START_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+ logUserJourneyBegin(msg.arg1, USER_JOURNEY_USER_START);
mInjector.onUserStarting(/* userId= */ msg.arg1);
scheduleOnUserCompletedEvent(msg.arg1,
UserCompletedEventType.EVENT_TYPE_USER_STARTING,
USER_COMPLETED_EVENT_DELAY_MS);
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_START_USER,
- USER_LIFECYCLE_EVENT_STATE_FINISH);
- clearSessionId(msg.arg1, USER_JOURNEY_USER_START);
+ mInjector.getUserJourneyLogger().logUserJourneyFinish(-1 , getUserInfo(msg.arg1),
+ USER_JOURNEY_USER_START);
break;
case USER_UNLOCK_MSG:
final int userId = msg.arg1;
@@ -3180,10 +3121,11 @@ class UserController implements Handler.Callback {
FgThread.getHandler().post(() -> {
mInjector.loadUserRecents(userId);
});
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_UNLOCKING_USER,
- USER_LIFECYCLE_EVENT_STATE_FINISH);
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_UNLOCKED_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+
+ mInjector.getUserJourneyLogger().logUserLifecycleEvent(msg.arg1,
+ USER_LIFECYCLE_EVENT_UNLOCKING_USER, EVENT_STATE_FINISH);
+ mInjector.getUserJourneyLogger().logUserLifecycleEvent(msg.arg1,
+ USER_LIFECYCLE_EVENT_UNLOCKED_USER, EVENT_STATE_BEGIN);
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("finishUserUnlocked-" + userId);
@@ -3199,9 +3141,9 @@ class UserController implements Handler.Callback {
// (No need to acquire lock to read mCurrentUserId since it is volatile.)
// TODO: Find something to wait for in the case of a profile.
mCurrentUserId == msg.arg1 ? USER_COMPLETED_EVENT_DELAY_MS : 1000);
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_UNLOCKED_USER,
- USER_LIFECYCLE_EVENT_STATE_FINISH);
- clearSessionId(msg.arg1);
+ mInjector.getUserJourneyLogger().logUserLifecycleEvent(msg.arg1,
+ USER_LIFECYCLE_EVENT_UNLOCKED_USER, EVENT_STATE_FINISH);
+ // Unlocking user is not a journey no need to clear sessionId
break;
case USER_CURRENT_MSG:
mInjector.batteryStatsServiceNoteEvent(
@@ -3224,22 +3166,24 @@ class UserController implements Handler.Callback {
break;
case REPORT_USER_SWITCH_COMPLETE_MSG:
dispatchUserSwitchComplete(msg.arg1, msg.arg2);
- logUserLifecycleEvent(msg.arg2, USER_LIFECYCLE_EVENT_SWITCH_USER,
- USER_LIFECYCLE_EVENT_STATE_FINISH);
+ UserJourneySession session = mInjector.getUserJourneyLogger()
+ .logUserSwitchJourneyFinish(msg.arg1, getUserInfo(msg.arg2));
+ if (session != null) {
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, session);
+ }
break;
case REPORT_LOCKED_BOOT_COMPLETE_MSG:
dispatchLockedBootComplete(msg.arg1);
break;
case START_USER_SWITCH_UI_MSG:
final Pair<UserInfo, UserInfo> fromToUserPair = (Pair<UserInfo, UserInfo>) msg.obj;
- logUserJourneyInfo(fromToUserPair.first, fromToUserPair.second,
- USER_JOURNEY_USER_SWITCH_UI);
- logUserLifecycleEvent(fromToUserPair.second.id, USER_LIFECYCLE_EVENT_SWITCH_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+ logUserJourneyBegin(fromToUserPair.second.id, USER_JOURNEY_USER_SWITCH_UI);
showUserSwitchDialog(fromToUserPair);
break;
case CLEAR_USER_JOURNEY_SESSION_MSG:
- logAndClearSessionId(msg.arg1);
+ mInjector.getUserJourneyLogger()
+ .finishAndClearIncompleteUserJourney(msg.arg1, msg.arg2);
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, msg.obj);
break;
case COMPLETE_USER_SWITCH_MSG:
completeUserSwitch(msg.arg1, msg.arg2);
@@ -3317,123 +3261,29 @@ class UserController implements Handler.Callback {
* statsd helper method for logging the start of a user journey via a UserLifecycleEventOccurred
* atom given the originating and targeting users for the journey.
*/
- private void logUserJourneyInfo(UserInfo origin, UserInfo target, @UserJourney int journey) {
- final long newSessionId = ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE);
- synchronized (mUserIdToUserJourneyMap) {
- UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(target.id);
- if (userJourneySession != null) {
- // TODO(b/157007231): Move this logic to a separate class/file.
- if ((userJourneySession.mJourney == USER_JOURNEY_USER_SWITCH_UI
- || userJourneySession.mJourney == USER_JOURNEY_USER_SWITCH_FG)
- && (journey == USER_JOURNEY_USER_START
- || journey == USER_JOURNEY_USER_STOP)) {
- /*
- * There is already a user switch journey, and a user start or stop journey for
- * the same target user received. New journey is most likely a part of user
- * switch journey so no need to create a new journey.
- */
- if (DEBUG_MU) {
- Slogf.d(TAG, journey + " not logged as it is expected to be part of "
- + userJourneySession.mJourney);
- }
- return;
- }
- /*
- * Possible reasons for this condition to be true:
- * - A user switch journey is received while another user switch journey is in
- * process for the same user.
- * - A user switch journey is received while user start journey is in process for
- * the same user.
- * - A user start journey is received while another user start journey is in process
- * for the same user.
- * In all cases potentially an incomplete, timed-out session or multiple
- * simultaneous requests. It is not possible to keep track of multiple sessions for
- * the same user, so previous session is abandoned.
- */
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED,
- userJourneySession.mSessionId, target.id, USER_LIFECYCLE_EVENT_UNKNOWN,
- USER_LIFECYCLE_EVENT_STATE_NONE);
- }
-
+ private void logUserJourneyBegin(int targetId,
+ @UserJourneyLogger.UserJourney int journey) {
+ UserJourneySession oldSession = mInjector.getUserJourneyLogger()
+ .finishAndClearIncompleteUserJourney(targetId, journey);
+ if (oldSession != null) {
if (DEBUG_MU) {
Slogf.d(TAG,
- "Starting a new journey: " + journey + " with session id: " + newSessionId);
+ "Starting a new journey: " + journey + " with session id: "
+ + oldSession);
}
-
- userJourneySession = new UserJourneySession(newSessionId, journey);
- mUserIdToUserJourneyMap.put(target.id, userJourneySession);
/*
- * User lifecyle journey would be complete when {@code #clearSessionId} is called after
- * the last expected lifecycle event for the journey. It may be possible that the last
- * event is not called, e.g., user not unlocked after user switching. In such cases user
- * journey is cleared after {@link USER_JOURNEY_TIMEOUT}.
+ * User lifecycle journey would be complete when {@code #clearSessionId} is called
+ * after the last expected lifecycle event for the journey. It may be possible that
+ * the last event is not called, e.g., user not unlocked after user switching. In such
+ * cases user journey is cleared after {@link USER_JOURNEY_TIMEOUT}.
*/
- mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(CLEAR_USER_JOURNEY_SESSION_MSG,
- target.id, /* arg2= */ 0), USER_JOURNEY_TIMEOUT_MS);
- }
-
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED, newSessionId,
- journey, origin != null ? origin.id : -1,
- target.id, UserManager.getUserTypeForStatsd(target.userType), target.flags);
- }
-
- /**
- * statsd helper method for logging the given event for the UserLifecycleEventOccurred statsd
- * atom.
- */
- private void logUserLifecycleEvent(@UserIdInt int userId, @UserLifecycleEvent int event,
- @UserLifecycleEventState int eventState) {
- final long sessionId;
- synchronized (mUserIdToUserJourneyMap) {
- final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(userId);
- if (userJourneySession == null || userJourneySession.mSessionId == INVALID_SESSION_ID) {
- Slogf.w(TAG, "UserLifecycleEvent " + event
- + " received without an active userJourneySession.");
- return;
- }
- sessionId = userJourneySession.mSessionId;
- }
-
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId,
- event, eventState);
- }
-
- /**
- * Clears the {@link UserJourneySession} for a given {@link UserIdInt} and {@link UserJourney}.
- */
- private void clearSessionId(@UserIdInt int userId, @UserJourney int journey) {
- synchronized (mUserIdToUserJourneyMap) {
- final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(userId);
- if (userJourneySession != null && userJourneySession.mJourney == journey) {
- clearSessionId(userId);
- }
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, oldSession);
}
- }
+ UserJourneySession newSession = mInjector.getUserJourneyLogger()
+ .logUserJourneyBegin(targetId, journey);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(CLEAR_USER_JOURNEY_SESSION_MSG,
+ targetId, /* arg2= */ journey, newSession), USER_JOURNEY_TIMEOUT_MS);
- /**
- * Clears the {@link UserJourneySession} for a given {@link UserIdInt}.
- */
- private void clearSessionId(@UserIdInt int userId) {
- synchronized (mUserIdToUserJourneyMap) {
- mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG);
- mUserIdToUserJourneyMap.delete(userId);
- }
- }
-
- /**
- * Log a final event of the {@link UserJourneySession} and clear it.
- */
- private void logAndClearSessionId(@UserIdInt int userId) {
- synchronized (mUserIdToUserJourneyMap) {
- final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(userId);
- if (userJourneySession != null) {
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED,
- userJourneySession.mSessionId, userId, USER_LIFECYCLE_EVENT_UNKNOWN,
- USER_LIFECYCLE_EVENT_STATE_NONE);
- }
- clearSessionId(userId);
- }
}
private BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
@@ -3471,23 +3321,6 @@ class UserController implements Handler.Callback {
return mLastUserUnlockingUptime;
}
- /**
- * Helper class to store user journey and session id.
- *
- * <p> User journey tracks a chain of user lifecycle events occurring during different user
- * activities such as user start, user switch, and user creation.
- */
- // TODO(b/157007231): Move this class and user journey tracking logic to a separate file.
- private static class UserJourneySession {
- final long mSessionId;
- @UserJourney final int mJourney;
-
- UserJourneySession(long sessionId, @UserJourney int journey) {
- mJourney = journey;
- mSessionId = sessionId;
- }
- }
-
private static class UserProgressListener extends IProgressListener.Stub {
private volatile long mUnlockStarted;
@Override
@@ -3562,6 +3395,10 @@ class UserController implements Handler.Callback {
return new Handler(mService.mUiHandler.getLooper(), callback);
}
+ protected UserJourneyLogger getUserJourneyLogger() {
+ return getUserManager().getUserJourneyLogger();
+ }
+
protected Context getContext() {
return mService.mContext;
}
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 6da6a6ecda52..4e7865c2d7a6 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -33,6 +33,8 @@ import android.graphics.Shader;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
@@ -53,6 +55,8 @@ import com.android.internal.util.ObjectUtils;
import com.android.internal.util.UserIcons;
import com.android.server.wm.WindowManagerService;
+import java.util.concurrent.atomic.AtomicBoolean;
+
/**
* Dialog to show during the user switch. This dialog shows target user's name and their profile
* picture with a circular spinner animation around it if the animations for this dialog are not
@@ -64,9 +68,14 @@ class UserSwitchingDialog extends Dialog {
// User switching doesn't happen that frequently, so it doesn't hurt to have it always on
protected static final boolean DEBUG = true;
+
private static final long DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS = 300;
private final boolean mDisableAnimations;
+ // Time to wait for the onAnimationEnd() callbacks before moving on
+ private static final int ANIMATION_TIMEOUT_MS = 1000;
+ private final Handler mHandler = new Handler(Looper.myLooper());
+
protected final UserInfo mOldUser;
protected final UserInfo mNewUser;
private final String mSwitchingFromSystemUserMessage;
@@ -180,7 +189,7 @@ class UserSwitchingDialog extends Dialog {
@Override
public void show() {
- asyncTraceBegin("", 0);
+ asyncTraceBegin("dialog", 0);
super.show();
}
@@ -188,7 +197,7 @@ class UserSwitchingDialog extends Dialog {
public void dismiss() {
super.dismiss();
stopFreezingScreen();
- asyncTraceEnd("", 0);
+ asyncTraceEnd("dialog", 0);
}
public void show(@NonNull Runnable onShown) {
@@ -217,20 +226,18 @@ class UserSwitchingDialog extends Dialog {
if (!mNeedToFreezeScreen) {
return;
}
- if (DEBUG) Slog.d(TAG, "startFreezingScreen");
- Trace.traceBegin(TRACE_TAG, "startFreezingScreen");
+ traceBegin("startFreezingScreen");
mWindowManager.startFreezingScreen(0, 0);
- Trace.traceEnd(TRACE_TAG);
+ traceEnd("startFreezingScreen");
}
private void stopFreezingScreen() {
if (!mNeedToFreezeScreen) {
return;
}
- if (DEBUG) Slog.d(TAG, "stopFreezingScreen");
- Trace.traceBegin(TRACE_TAG, "stopFreezingScreen");
+ traceBegin("stopFreezingScreen");
mWindowManager.stopFreezingScreen();
- Trace.traceEnd(TRACE_TAG);
+ traceEnd("stopFreezingScreen");
}
private void startShowAnimation(Runnable onAnimationEnd) {
@@ -238,13 +245,13 @@ class UserSwitchingDialog extends Dialog {
onAnimationEnd.run();
return;
}
- asyncTraceBegin("-showAnimation", 1);
- startDialogAnimation(new AlphaAnimation(0, 1), () -> {
- asyncTraceEnd("-showAnimation", 1);
+ asyncTraceBegin("showAnimation", 1);
+ startDialogAnimation("show", new AlphaAnimation(0, 1), () -> {
+ asyncTraceEnd("showAnimation", 1);
- asyncTraceBegin("-spinnerAnimation", 2);
+ asyncTraceBegin("spinnerAnimation", 2);
startProgressAnimation(() -> {
- asyncTraceEnd("-spinnerAnimation", 2);
+ asyncTraceEnd("spinnerAnimation", 2);
onAnimationEnd.run();
});
@@ -257,31 +264,48 @@ class UserSwitchingDialog extends Dialog {
onAnimationEnd.run();
return;
}
- asyncTraceBegin("-dismissAnimation", 3);
- startDialogAnimation(new AlphaAnimation(1, 0), () -> {
- asyncTraceEnd("-dismissAnimation", 3);
+ asyncTraceBegin("dismissAnimation", 3);
+ startDialogAnimation("dismiss", new AlphaAnimation(1, 0), () -> {
+ asyncTraceEnd("dismissAnimation", 3);
onAnimationEnd.run();
});
}
private void startProgressAnimation(Runnable onAnimationEnd) {
- if (mDisableAnimations) {
+ final AnimatedVectorDrawable avd = getSpinnerAVD();
+ if (mDisableAnimations || avd == null) {
onAnimationEnd.run();
return;
}
- final ImageView progressCircular = findViewById(R.id.progress_circular);
- final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) progressCircular.getDrawable();
+ final Runnable onAnimationEndWithTimeout = animationWithTimeout("spinner", onAnimationEnd);
avd.registerAnimationCallback(new Animatable2.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
- onAnimationEnd.run();
+ onAnimationEndWithTimeout.run();
}
});
avd.start();
}
- private void startDialogAnimation(Animation animation, Runnable onAnimationEnd) {
+ private AnimatedVectorDrawable getSpinnerAVD() {
+ final ImageView view = findViewById(R.id.progress_circular);
+ if (view != null) {
+ final Drawable drawable = view.getDrawable();
+ if (drawable instanceof AnimatedVectorDrawable) {
+ return (AnimatedVectorDrawable) drawable;
+ }
+ }
+ return null;
+ }
+
+ private void startDialogAnimation(String name, Animation animation, Runnable onAnimationEnd) {
+ final View view = findViewById(R.id.content);
+ if (mDisableAnimations || view == null) {
+ onAnimationEnd.run();
+ return;
+ }
+ final Runnable onAnimationEndWithTimeout = animationWithTimeout(name, onAnimationEnd);
animation.setDuration(DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
@@ -291,7 +315,7 @@ class UserSwitchingDialog extends Dialog {
@Override
public void onAnimationEnd(Animation animation) {
- onAnimationEnd.run();
+ onAnimationEndWithTimeout.run();
}
@Override
@@ -299,14 +323,42 @@ class UserSwitchingDialog extends Dialog {
}
});
- findViewById(R.id.content).startAnimation(animation);
+ view.startAnimation(animation);
+ }
+
+ private Runnable animationWithTimeout(String name, Runnable onAnimationEnd) {
+ final AtomicBoolean isFirst = new AtomicBoolean(true);
+ final Runnable onAnimationEndOrTimeout = () -> {
+ if (isFirst.getAndSet(false)) {
+ mHandler.removeCallbacksAndMessages(null);
+ onAnimationEnd.run();
+ }
+ };
+ mHandler.postDelayed(() -> {
+ Slog.w(TAG, name + " animation not completed in " + ANIMATION_TIMEOUT_MS + " ms");
+ onAnimationEndOrTimeout.run();
+ }, ANIMATION_TIMEOUT_MS);
+
+ return onAnimationEndOrTimeout;
}
private void asyncTraceBegin(String subTag, int subCookie) {
+ if (DEBUG) Slog.d(TAG, "asyncTraceBegin-" + subTag);
Trace.asyncTraceBegin(TRACE_TAG, TAG + subTag, mTraceCookie + subCookie);
}
private void asyncTraceEnd(String subTag, int subCookie) {
Trace.asyncTraceEnd(TRACE_TAG, TAG + subTag, mTraceCookie + subCookie);
+ if (DEBUG) Slog.d(TAG, "asyncTraceEnd-" + subTag);
+ }
+
+ private void traceBegin(String msg) {
+ if (DEBUG) Slog.d(TAG, "traceBegin-" + msg);
+ Trace.traceBegin(TRACE_TAG, msg);
+ }
+
+ private void traceEnd(String msg) {
+ Trace.traceEnd(TRACE_TAG);
+ if (DEBUG) Slog.d(TAG, "traceEnd-" + msg);
}
}
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index d369af608d31..e4a5a3e0ed00 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -402,11 +402,15 @@ public final class GameManagerService extends IGameManagerService.Stub {
public enum FrameRate {
FPS_DEFAULT(0),
FPS_30(30),
+ FPS_36(36),
FPS_40(40),
FPS_45(45),
+ FPS_48(48),
FPS_60(60),
+ FPS_72(72),
FPS_90(90),
FPS_120(120),
+ FPS_144(144),
FPS_INVALID(-1);
public final int fps;
@@ -423,16 +427,24 @@ public final class GameManagerService extends IGameManagerService.Stub {
switch (raw) {
case "30":
return FrameRate.FPS_30.fps;
+ case "36":
+ return FrameRate.FPS_36.fps;
case "40":
return FrameRate.FPS_40.fps;
case "45":
return FrameRate.FPS_45.fps;
+ case "48":
+ return FrameRate.FPS_48.fps;
case "60":
return FrameRate.FPS_60.fps;
+ case "72":
+ return FrameRate.FPS_72.fps;
case "90":
return FrameRate.FPS_90.fps;
case "120":
return FrameRate.FPS_120.fps;
+ case "144":
+ return FrameRate.FPS_144.fps;
case "disable":
case "":
return FrameRate.FPS_DEFAULT.fps;
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index ada92f5545c2..bc4e8df2a4ad 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -88,14 +88,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
private final @NonNull AudioSystemAdapter mAudioSystem;
/** ID for Communication strategy retrieved form audio policy manager */
- private int mCommunicationStrategyId = -1;
+ /*package*/ int mCommunicationStrategyId = -1;
/** ID for Accessibility strategy retrieved form audio policy manager */
private int mAccessibilityStrategyId = -1;
/** Active communication device reported by audio policy manager */
- private AudioDeviceInfo mActiveCommunicationDevice;
+ /*package*/ AudioDeviceInfo mActiveCommunicationDevice;
/** Last preferred device set for communication strategy */
private AudioDeviceAttributes mPreferredCommunicationDevice;
@@ -755,6 +755,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
mIsLeOutput = false;
}
+ BtDeviceInfo(@NonNull BtDeviceInfo src, int state) {
+ mDevice = src.mDevice;
+ mState = state;
+ mProfile = src.mProfile;
+ mSupprNoisy = src.mSupprNoisy;
+ mVolume = src.mVolume;
+ mIsLeOutput = src.mIsLeOutput;
+ mEventSource = src.mEventSource;
+ mAudioSystemDevice = src.mAudioSystemDevice;
+ mMusicDevice = src.mMusicDevice;
+ mCodec = src.mCodec;
+ }
+
// redefine equality op so we can match messages intended for this device
@Override
public boolean equals(Object o) {
@@ -821,7 +834,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @param info struct with the (dis)connection information
*/
/*package*/ void queueOnBluetoothActiveDeviceChanged(@NonNull BtDeviceChangedData data) {
- if (data.mInfo.getProfile() == BluetoothProfile.A2DP && data.mPreviousDevice != null
+ if (data.mPreviousDevice != null
&& data.mPreviousDevice.equals(data.mNewDevice)) {
final String name = TextUtils.emptyIfNull(data.mNewDevice.getName());
new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
@@ -830,7 +843,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
.set(MediaMetrics.Property.STATUS, data.mInfo.getProfile())
.record();
synchronized (mDeviceStateLock) {
- postBluetoothA2dpDeviceConfigChange(data.mNewDevice);
+ postBluetoothDeviceConfigChange(createBtDeviceInfo(data, data.mNewDevice,
+ BluetoothProfile.STATE_CONNECTED));
}
} else {
synchronized (mDeviceStateLock) {
@@ -1064,8 +1078,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
new AudioModeInfo(mode, pid, uid));
}
- /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
- sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device);
+ /*package*/ void postBluetoothDeviceConfigChange(@NonNull BtDeviceInfo info) {
+ sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info);
}
/*package*/ void startBluetoothScoForClient(IBinder cb, int pid, int scoAudioMode,
@@ -1092,21 +1106,21 @@ import java.util.concurrent.atomic.AtomicBoolean;
/*package*/ int setPreferredDevicesForStrategySync(int strategy,
@NonNull List<AudioDeviceAttributes> devices) {
- return mDeviceInventory.setPreferredDevicesForStrategySync(strategy, devices);
+ return mDeviceInventory.setPreferredDevicesForStrategyAndSave(strategy, devices);
}
/*package*/ int removePreferredDevicesForStrategySync(int strategy) {
- return mDeviceInventory.removePreferredDevicesForStrategySync(strategy);
+ return mDeviceInventory.removePreferredDevicesForStrategyAndSave(strategy);
}
/*package*/ int setDeviceAsNonDefaultForStrategySync(int strategy,
@NonNull AudioDeviceAttributes device) {
- return mDeviceInventory.setDeviceAsNonDefaultForStrategySync(strategy, device);
+ return mDeviceInventory.setDeviceAsNonDefaultForStrategyAndSave(strategy, device);
}
/*package*/ int removeDeviceAsNonDefaultForStrategySync(int strategy,
@NonNull AudioDeviceAttributes device) {
- return mDeviceInventory.removeDeviceAsNonDefaultForStrategySync(strategy, device);
+ return mDeviceInventory.removeDeviceAsNonDefaultForStrategyAndSave(strategy, device);
}
/*package*/ void registerStrategyPreferredDevicesDispatcher(
@@ -1131,11 +1145,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
/*package*/ int setPreferredDevicesForCapturePresetSync(int capturePreset,
@NonNull List<AudioDeviceAttributes> devices) {
- return mDeviceInventory.setPreferredDevicesForCapturePresetSync(capturePreset, devices);
+ return mDeviceInventory.setPreferredDevicesForCapturePresetAndSave(capturePreset, devices);
}
/*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) {
- return mDeviceInventory.clearPreferredDevicesForCapturePresetSync(capturePreset);
+ return mDeviceInventory.clearPreferredDevicesForCapturePresetAndSave(capturePreset);
}
/*package*/ void registerCapturePresetDevicesRoleDispatcher(
@@ -1322,6 +1336,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state);
}
+ /*package*/ void postNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) {
+ sendLMsgNoDelay(MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED, SENDMSG_QUEUE, btDevice);
+ }
+
/*package*/ static final class CommunicationDeviceInfo {
final @NonNull IBinder mCb; // Identifies the requesting client for death handler
final int mPid; // Requester process ID
@@ -1397,9 +1415,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
- /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect) {
+ /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes,
+ boolean connect, @Nullable BluetoothDevice btDevice) {
synchronized (mDeviceStateLock) {
- return mDeviceInventory.handleDeviceConnection(attributes, connect, false /*for test*/);
+ return mDeviceInventory.handleDeviceConnection(
+ attributes, connect, false /*for test*/, btDevice);
}
}
@@ -1640,13 +1660,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
(String) msg.obj, msg.arg1);
}
break;
- case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
- final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
+ case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
synchronized (mDeviceStateLock) {
- final int a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
- mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
- new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec),
- BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
+ mDeviceInventory.onBluetoothDeviceConfigChange(
+ (BtDeviceInfo) msg.obj, BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
}
break;
case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
@@ -1810,6 +1827,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
case MSG_IL_SET_LEAUDIO_SUSPENDED: {
setLeAudioSuspended((msg.arg1 == 1), false /*internal*/, (String) msg.obj);
} break;
+ case MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED: {
+ final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
+ BtHelper.onNotifyPreferredAudioProfileApplied(btDevice);
+ } break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -1845,7 +1866,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_IL_BTA2DP_TIMEOUT = 10;
// process change of A2DP device configuration, obj is BluetoothDevice
- private static final int MSG_L_A2DP_DEVICE_CONFIG_CHANGE = 11;
+ private static final int MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE = 11;
private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 12;
private static final int MSG_REPORT_NEW_ROUTES = 13;
@@ -1887,13 +1908,15 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_IL_SET_A2DP_SUSPENDED = 50;
private static final int MSG_IL_SET_LEAUDIO_SUSPENDED = 51;
+ private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 52;
+
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_L_SET_BT_ACTIVE_DEVICE:
case MSG_IL_BTA2DP_TIMEOUT:
case MSG_IL_BTLEAUDIO_TIMEOUT:
- case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
+ case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
case MSG_TOGGLE_HDMI:
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
@@ -1985,7 +2008,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_IL_BTA2DP_TIMEOUT:
case MSG_IL_BTLEAUDIO_TIMEOUT:
- case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
+ case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
if (sLastDeviceConnectMsgTime >= time) {
// add a little delay to make sure messages are ordered as expected
time = sLastDeviceConnectMsgTime + 30;
@@ -2005,7 +2028,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
static {
MESSAGES_MUTE_MUSIC = new HashSet<>();
MESSAGES_MUTE_MUSIC.add(MSG_L_SET_BT_ACTIVE_DEVICE);
- MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE);
+ MESSAGES_MUTE_MUSIC.add(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT);
MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE);
}
@@ -2026,7 +2049,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
// Do not mute on bluetooth event if music is playing on a wired headset.
if ((message == MSG_L_SET_BT_ACTIVE_DEVICE
|| message == MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT
- || message == MSG_L_A2DP_DEVICE_CONFIG_CHANGE)
+ || message == MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE)
&& AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)
&& hasIntersection(mDeviceInventory.DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET,
mAudioService.getDeviceSetForStream(AudioSystem.STREAM_MUSIC))) {
@@ -2165,18 +2188,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (preferredCommunicationDevice == null) {
AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice();
if (defaultDevice != null) {
- setPreferredDevicesForStrategySync(
+ mDeviceInventory.setPreferredDevicesForStrategy(
mCommunicationStrategyId, Arrays.asList(defaultDevice));
- setPreferredDevicesForStrategySync(
+ mDeviceInventory.setPreferredDevicesForStrategy(
mAccessibilityStrategyId, Arrays.asList(defaultDevice));
} else {
- removePreferredDevicesForStrategySync(mCommunicationStrategyId);
- removePreferredDevicesForStrategySync(mAccessibilityStrategyId);
+ mDeviceInventory.removePreferredDevicesForStrategy(mCommunicationStrategyId);
+ mDeviceInventory.removePreferredDevicesForStrategy(mAccessibilityStrategyId);
}
+ mDeviceInventory.applyConnectedDevicesRoles();
} else {
- setPreferredDevicesForStrategySync(
+ mDeviceInventory.setPreferredDevicesForStrategy(
mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
- setPreferredDevicesForStrategySync(
+ mDeviceInventory.setPreferredDevicesForStrategy(
mAccessibilityStrategyId, Arrays.asList(preferredCommunicationDevice));
}
onUpdatePhoneStrategyDevice(preferredCommunicationDevice);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 228bc87cc20b..773df3720ed3 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -34,26 +34,36 @@ import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.IStrategyNonDefaultDevicesDispatcher;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.MediaMetrics;
+import android.media.MediaRecorder.AudioSource;
+import android.media.audiopolicy.AudioProductStrategy;
import android.media.permission.ClearCallingIdentityContext;
import android.media.permission.SafeCloseable;
import android.os.Binder;
+import android.os.Bundle;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.utils.EventLogger;
+import com.google.android.collect.Sets;
+
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -175,18 +185,26 @@ public class AudioDeviceInventory {
final RemoteCallbackList<ICapturePresetDevicesRoleDispatcher> mDevRoleCapturePresetDispatchers =
new RemoteCallbackList<ICapturePresetDevicesRoleDispatcher>();
+ final List<AudioProductStrategy> mStrategies;
+
/*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) {
- mDeviceBroker = broker;
- mAudioSystem = AudioSystemAdapter.getDefaultAdapter();
+ this(broker, AudioSystemAdapter.getDefaultAdapter());
}
//-----------------------------------------------------------
/** for mocking only, allows to inject AudioSystem adapter */
/*package*/ AudioDeviceInventory(@NonNull AudioSystemAdapter audioSystem) {
- mDeviceBroker = null;
- mAudioSystem = audioSystem;
+ this(null, audioSystem);
}
+ private AudioDeviceInventory(@Nullable AudioDeviceBroker broker,
+ @Nullable AudioSystemAdapter audioSystem) {
+ mDeviceBroker = broker;
+ mAudioSystem = audioSystem;
+ mStrategies = AudioProductStrategy.getAudioProductStrategies();
+ mBluetoothDualModeEnabled = SystemProperties.getBoolean(
+ "persist.bluetooth.enable_dual_mode_audio", false);
+ }
/*package*/ void setDeviceBroker(@NonNull AudioDeviceBroker broker) {
mDeviceBroker = broker;
}
@@ -203,8 +221,13 @@ public class AudioDeviceInventory {
int mDeviceCodecFormat;
final UUID mSensorUuid;
+ /** Disabled operating modes for this device. Use a negative logic so that by default
+ * an empty list means all modes are allowed.
+ * See BluetoothAdapter.AUDIO_MODE_DUPLEX and BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY */
+ @NonNull ArraySet<String> mDisabledModes = new ArraySet(0);
+
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
- int deviceCodecFormat, UUID sensorUuid) {
+ int deviceCodecFormat, @Nullable UUID sensorUuid) {
mDeviceType = deviceType;
mDeviceName = deviceName == null ? "" : deviceName;
mDeviceAddress = deviceAddress == null ? "" : deviceAddress;
@@ -212,11 +235,31 @@ public class AudioDeviceInventory {
mSensorUuid = sensorUuid;
}
+ void setModeDisabled(String mode) {
+ mDisabledModes.add(mode);
+ }
+ void setModeEnabled(String mode) {
+ mDisabledModes.remove(mode);
+ }
+ boolean isModeEnabled(String mode) {
+ return !mDisabledModes.contains(mode);
+ }
+ boolean isOutputOnlyModeEnabled() {
+ return isModeEnabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
+ }
+ boolean isDuplexModeEnabled() {
+ return isModeEnabled(BluetoothAdapter.AUDIO_MODE_DUPLEX);
+ }
+
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
int deviceCodecFormat) {
this(deviceType, deviceName, deviceAddress, deviceCodecFormat, null);
}
+ DeviceInfo(int deviceType, String deviceName, String deviceAddress) {
+ this(deviceType, deviceName, deviceAddress, AudioSystem.AUDIO_FORMAT_DEFAULT);
+ }
+
@Override
public String toString() {
return "[DeviceInfo: type:0x" + Integer.toHexString(mDeviceType)
@@ -224,7 +267,8 @@ public class AudioDeviceInventory {
+ ") name:" + mDeviceName
+ " addr:" + mDeviceAddress
+ " codec: " + Integer.toHexString(mDeviceCodecFormat)
- + " sensorUuid: " + Objects.toString(mSensorUuid) + "]";
+ + " sensorUuid: " + Objects.toString(mSensorUuid)
+ + " disabled modes: " + mDisabledModes + "]";
}
@NonNull String getKey() {
@@ -276,9 +320,18 @@ public class AudioDeviceInventory {
pw.println(" " + prefix + " type:0x" + Integer.toHexString(keyType)
+ " (" + AudioSystem.getDeviceName(keyType)
+ ") addr:" + valueAddress); });
+ pw.println("\n" + prefix + "Preferred devices for capture preset:");
mPreferredDevicesForCapturePreset.forEach((capturePreset, devices) -> {
pw.println(" " + prefix + "capturePreset:" + capturePreset
+ " devices:" + devices); });
+ pw.println("\n" + prefix + "Applied devices roles for strategies:");
+ mAppliedStrategyRoles.forEach((key, devices) -> {
+ pw.println(" " + prefix + "strategy: " + key.first
+ + " role:" + key.second + " devices:" + devices); });
+ pw.println("\n" + prefix + "Applied devices roles for presets:");
+ mAppliedPresetRoles.forEach((key, devices) -> {
+ pw.println(" " + prefix + "preset: " + key.first
+ + " role:" + key.second + " devices:" + devices); });
}
//------------------------------------------------------------
@@ -299,15 +352,16 @@ public class AudioDeviceInventory {
AudioSystem.DEVICE_STATE_AVAILABLE,
di.mDeviceCodecFormat);
}
+ mAppliedStrategyRoles.clear();
+ applyConnectedDevicesRoles_l();
}
synchronized (mPreferredDevices) {
mPreferredDevices.forEach((strategy, devices) -> {
- mAudioSystem.setDevicesRoleForStrategy(
- strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); });
+ setPreferredDevicesForStrategy(strategy, devices); });
}
synchronized (mNonDefaultDevices) {
mNonDefaultDevices.forEach((strategy, devices) -> {
- mAudioSystem.setDevicesRoleForStrategy(
+ addDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_DISABLED, devices); });
}
synchronized (mPreferredDevicesForCapturePreset) {
@@ -380,8 +434,7 @@ public class AudioDeviceInventory {
btInfo.mVolume * 10, btInfo.mAudioSystemDevice,
"onSetBtActiveDevice");
}
- makeA2dpDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
- "onSetBtActiveDevice", btInfo.mCodec);
+ makeA2dpDeviceAvailable(btInfo, "onSetBtActiveDevice");
}
break;
case BluetoothProfile.HEARING_AID:
@@ -397,10 +450,7 @@ public class AudioDeviceInventory {
if (switchToUnavailable) {
makeLeAudioDeviceUnavailableNow(address, btInfo.mAudioSystemDevice);
} else if (switchToAvailable) {
- makeLeAudioDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
- streamType, btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10,
- btInfo.mAudioSystemDevice,
- "onSetBtActiveDevice");
+ makeLeAudioDeviceAvailable(btInfo, streamType, "onSetBtActiveDevice");
}
break;
default: throw new IllegalArgumentException("Invalid profile "
@@ -411,30 +461,30 @@ public class AudioDeviceInventory {
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- /*package*/ void onBluetoothA2dpDeviceConfigChange(
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) {
+ /*package*/ void onBluetoothDeviceConfigChange(
+ @NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int event) {
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
- + "onBluetoothA2dpDeviceConfigChange")
- .set(MediaMetrics.Property.EVENT, BtHelper.a2dpDeviceEventToString(event));
+ + "onBluetoothDeviceConfigChange")
+ .set(MediaMetrics.Property.EVENT, BtHelper.deviceEventToString(event));
- final BluetoothDevice btDevice = btInfo.getBtDevice();
+ final BluetoothDevice btDevice = btInfo.mDevice;
if (btDevice == null) {
mmi.set(MediaMetrics.Property.EARLY_RETURN, "btDevice null").record();
return;
}
if (AudioService.DEBUG_DEVICES) {
- Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
+ Log.d(TAG, "onBluetoothDeviceConfigChange btDevice=" + btDevice);
}
- int a2dpVolume = btInfo.getVolume();
- @AudioSystem.AudioFormatNativeEnumForBtCodec final int a2dpCodec = btInfo.getCodec();
+ int volume = btInfo.mVolume;
+ @AudioSystem.AudioFormatNativeEnumForBtCodec final int audioCodec = btInfo.mCodec;
String address = btDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "onBluetoothA2dpDeviceConfigChange addr=" + address
- + " event=" + BtHelper.a2dpDeviceEventToString(event)));
+ "onBluetoothDeviceConfigChange addr=" + address
+ + " event=" + BtHelper.deviceEventToString(event)));
synchronized (mDevicesLock) {
if (mDeviceBroker.hasScheduledA2dpConnection(btDevice)) {
@@ -449,53 +499,53 @@ public class AudioDeviceInventory {
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
final DeviceInfo di = mConnectedDevices.get(key);
if (di == null) {
- Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpDeviceConfigChange");
+ Log.e(TAG, "invalid null DeviceInfo in onBluetoothDeviceConfigChange");
mmi.set(MediaMetrics.Property.EARLY_RETURN, "null DeviceInfo").record();
return;
}
mmi.set(MediaMetrics.Property.ADDRESS, address)
.set(MediaMetrics.Property.ENCODING,
- AudioSystem.audioFormatToString(a2dpCodec))
- .set(MediaMetrics.Property.INDEX, a2dpVolume)
+ AudioSystem.audioFormatToString(audioCodec))
+ .set(MediaMetrics.Property.INDEX, volume)
.set(MediaMetrics.Property.NAME, di.mDeviceName);
- if (event == BtHelper.EVENT_ACTIVE_DEVICE_CHANGE) {
- // Device is connected
- if (a2dpVolume != -1) {
- mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
- // convert index to internal representation in VolumeStreamState
- a2dpVolume * 10,
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- "onBluetoothA2dpDeviceConfigChange");
- }
- } else if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
- if (di.mDeviceCodecFormat != a2dpCodec) {
- di.mDeviceCodecFormat = a2dpCodec;
- mConnectedDevices.replace(key, di);
- }
- }
- final int res = mAudioSystem.handleDeviceConfigChange(
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address,
- BtHelper.getName(btDevice), a2dpCodec);
- if (res != AudioSystem.AUDIO_STATUS_OK) {
- AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "APM handleDeviceConfigChange failed for A2DP device addr=" + address
- + " codec=" + AudioSystem.audioFormatToString(a2dpCodec))
- .printLog(TAG));
+ if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
+ boolean a2dpCodecChange = false;
+ if (btInfo.mProfile == BluetoothProfile.A2DP) {
+ if (di.mDeviceCodecFormat != audioCodec) {
+ di.mDeviceCodecFormat = audioCodec;
+ mConnectedDevices.replace(key, di);
+ a2dpCodecChange = true;
+ }
+ final int res = mAudioSystem.handleDeviceConfigChange(
+ btInfo.mAudioSystemDevice, address,
+ BtHelper.getName(btDevice), audioCodec);
+
+ if (res != AudioSystem.AUDIO_STATUS_OK) {
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "APM handleDeviceConfigChange failed for A2DP device addr="
+ + address + " codec="
+ + AudioSystem.audioFormatToString(audioCodec))
+ .printLog(TAG));
+
+ // force A2DP device disconnection in case of error so that AudioService
+ // state is consistent with audio policy manager state
+ setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btInfo,
+ BluetoothProfile.STATE_DISCONNECTED));
+ } else {
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "APM handleDeviceConfigChange success for A2DP device addr="
+ + address
+ + " codec=" + AudioSystem.audioFormatToString(audioCodec))
+ .printLog(TAG));
- int musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC);
- // force A2DP device disconnection in case of error so that AudioService state is
- // consistent with audio policy manager state
- setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btDevice,
- BluetoothProfile.A2DP, BluetoothProfile.STATE_DISCONNECTED,
- musicDevice, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
- } else {
- AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "APM handleDeviceConfigChange success for A2DP device addr=" + address
- + " codec=" + AudioSystem.audioFormatToString(a2dpCodec))
- .printLog(TAG));
+ }
+ }
+ if (!a2dpCodecChange) {
+ updateBluetoothPreferredModes_l(btDevice /*connectedDevice*/);
+ }
}
}
mmi.record();
@@ -578,7 +628,7 @@ public class AudioDeviceInventory {
}
if (!handleDeviceConnection(wdcs.mAttributes,
- wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest)) {
+ wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest, null)) {
// change of connection state failed, bailout
mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed")
.record();
@@ -710,43 +760,51 @@ public class AudioDeviceInventory {
//------------------------------------------------------------
// preferred/non-default device(s)
- /*package*/ int setPreferredDevicesForStrategySync(int strategy,
+ /*package*/ int setPreferredDevicesForStrategyAndSave(int strategy,
@NonNull List<AudioDeviceAttributes> devices) {
- int status = AudioSystem.ERROR;
+ final int status = setPreferredDevicesForStrategy(strategy, devices);
+ if (status == AudioSystem.SUCCESS) {
+ mDeviceBroker.postSaveSetPreferredDevicesForStrategy(strategy, devices);
+ }
+ return status;
+ }
+ /*package*/ int setPreferredDevicesForStrategy(int strategy,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ int status = AudioSystem.ERROR;
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
- "setPreferredDevicesForStrategySync, strategy: " + strategy
+ "setPreferredDevicesForStrategy, strategy: " + strategy
+ " devices: " + devices)).printLog(TAG));
- status = mAudioSystem.setDevicesRoleForStrategy(
+ status = setDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
}
+ return status;
+ }
+ /*package*/ int removePreferredDevicesForStrategyAndSave(int strategy) {
+ final int status = removePreferredDevicesForStrategy(strategy);
if (status == AudioSystem.SUCCESS) {
- mDeviceBroker.postSaveSetPreferredDevicesForStrategy(strategy, devices);
+ mDeviceBroker.postSaveRemovePreferredDevicesForStrategy(strategy);
}
return status;
}
- /*package*/ int removePreferredDevicesForStrategySync(int strategy) {
+ /*package*/ int removePreferredDevicesForStrategy(int strategy) {
int status = AudioSystem.ERROR;
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
- "removePreferredDevicesForStrategySync, strategy: "
+ "removePreferredDevicesForStrategy, strategy: "
+ strategy)).printLog(TAG));
- status = mAudioSystem.clearDevicesRoleForStrategy(
+ status = clearDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_PREFERRED);
}
-
- if (status == AudioSystem.SUCCESS) {
- mDeviceBroker.postSaveRemovePreferredDevicesForStrategy(strategy);
- }
return status;
}
- /*package*/ int setDeviceAsNonDefaultForStrategySync(int strategy,
+ /*package*/ int setDeviceAsNonDefaultForStrategyAndSave(int strategy,
@NonNull AudioDeviceAttributes device) {
int status = AudioSystem.ERROR;
@@ -755,9 +813,9 @@ public class AudioDeviceInventory {
devices.add(device);
AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
- "setDeviceAsNonDefaultForStrategySync, strategy: " + strategy
+ "setDeviceAsNonDefaultForStrategyAndSave, strategy: " + strategy
+ " device: " + device)).printLog(TAG));
- status = mAudioSystem.setDevicesRoleForStrategy(
+ status = addDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_DISABLED, devices);
}
@@ -767,7 +825,7 @@ public class AudioDeviceInventory {
return status;
}
- /*package*/ int removeDeviceAsNonDefaultForStrategySync(int strategy,
+ /*package*/ int removeDeviceAsNonDefaultForStrategyAndSave(int strategy,
@NonNull AudioDeviceAttributes device) {
int status = AudioSystem.ERROR;
@@ -776,10 +834,10 @@ public class AudioDeviceInventory {
devices.add(device);
AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
- "removeDeviceAsNonDefaultForStrategySync, strategy: "
+ "removeDeviceAsNonDefaultForStrategyAndSave, strategy: "
+ strategy + " devices: " + device)).printLog(TAG));
- status = mAudioSystem.removeDevicesRoleForStrategy(
+ status = removeDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_DISABLED, devices);
}
@@ -810,35 +868,72 @@ public class AudioDeviceInventory {
mNonDefDevDispatchers.unregister(dispatcher);
}
- /*package*/ int setPreferredDevicesForCapturePresetSync(
+ /*package*/ int setPreferredDevicesForCapturePresetAndSave(
int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
- int status = AudioSystem.ERROR;
+ final int status = setPreferredDevicesForCapturePreset(capturePreset, devices);
+ if (status == AudioSystem.SUCCESS) {
+ mDeviceBroker.postSaveSetPreferredDevicesForCapturePreset(capturePreset, devices);
+ }
+ return status;
+ }
+ private int setPreferredDevicesForCapturePreset(
+ int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
+ int status = AudioSystem.ERROR;
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
- status = mAudioSystem.setDevicesRoleForCapturePreset(
+ status = setDevicesRoleForCapturePreset(
capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
}
+ return status;
+ }
+ /*package*/ int clearPreferredDevicesForCapturePresetAndSave(int capturePreset) {
+ final int status = clearPreferredDevicesForCapturePreset(capturePreset);
if (status == AudioSystem.SUCCESS) {
- mDeviceBroker.postSaveSetPreferredDevicesForCapturePreset(capturePreset, devices);
+ mDeviceBroker.postSaveClearPreferredDevicesForCapturePreset(capturePreset);
}
return status;
}
- /*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) {
+ private int clearPreferredDevicesForCapturePreset(int capturePreset) {
int status = AudioSystem.ERROR;
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
- status = mAudioSystem.clearDevicesRoleForCapturePreset(
+ status = clearDevicesRoleForCapturePreset(
capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED);
}
-
- if (status == AudioSystem.SUCCESS) {
- mDeviceBroker.postSaveClearPreferredDevicesForCapturePreset(capturePreset);
- }
return status;
}
+ private int addDevicesRoleForCapturePreset(int capturePreset, int role,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ return addDevicesRole(mAppliedPresetRoles, (p, r, d) -> {
+ return mAudioSystem.addDevicesRoleForCapturePreset(p, r, d);
+ }, capturePreset, role, devices);
+ }
+
+ private int removeDevicesRoleForCapturePreset(int capturePreset, int role,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ return removeDevicesRole(mAppliedPresetRoles, (p, r, d) -> {
+ return mAudioSystem.removeDevicesRoleForCapturePreset(p, r, d);
+ }, capturePreset, role, devices);
+ }
+
+ private int setDevicesRoleForCapturePreset(int capturePreset, int role,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ return setDevicesRole(mAppliedPresetRoles, (p, r, d) -> {
+ return mAudioSystem.addDevicesRoleForCapturePreset(p, r, d);
+ }, (p, r, d) -> {
+ return mAudioSystem.clearDevicesRoleForCapturePreset(p, r);
+ }, capturePreset, role, devices);
+ }
+
+ private int clearDevicesRoleForCapturePreset(int capturePreset, int role) {
+ return clearDevicesRole(mAppliedPresetRoles, (p, r, d) -> {
+ return mAudioSystem.clearDevicesRoleForCapturePreset(p, r);
+ }, capturePreset, role);
+ }
+
/*package*/ void registerCapturePresetDevicesRoleDispatcher(
@NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
mDevRoleCapturePresetDispatchers.register(dispatcher);
@@ -849,7 +944,208 @@ public class AudioDeviceInventory {
mDevRoleCapturePresetDispatchers.unregister(dispatcher);
}
- //-----------------------------------------------------------------------
+ private int addDevicesRoleForStrategy(int strategy, int role,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ return addDevicesRole(mAppliedStrategyRoles, (s, r, d) -> {
+ return mAudioSystem.setDevicesRoleForStrategy(s, r, d);
+ }, strategy, role, devices);
+ }
+
+ private int removeDevicesRoleForStrategy(int strategy, int role,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ return removeDevicesRole(mAppliedStrategyRoles, (s, r, d) -> {
+ return mAudioSystem.removeDevicesRoleForStrategy(s, r, d);
+ }, strategy, role, devices);
+ }
+
+ private int setDevicesRoleForStrategy(int strategy, int role,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ return setDevicesRole(mAppliedStrategyRoles, (s, r, d) -> {
+ return mAudioSystem.setDevicesRoleForStrategy(s, r, d);
+ }, (s, r, d) -> {
+ return mAudioSystem.clearDevicesRoleForStrategy(s, r);
+ }, strategy, role, devices);
+ }
+
+ private int clearDevicesRoleForStrategy(int strategy, int role) {
+ return clearDevicesRole(mAppliedStrategyRoles, (s, r, d) -> {
+ return mAudioSystem.clearDevicesRoleForStrategy(s, r);
+ }, strategy, role);
+ }
+
+ //------------------------------------------------------------
+ // Cache for applied roles for strategies and devices. The cache avoids reapplying the
+ // same list of devices for a given role and strategy and the corresponding systematic
+ // redundant work in audio policy manager and audio flinger.
+ // The key is the pair <Strategy , Role> and the value is the current list of devices.
+
+ private final ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>>
+ mAppliedStrategyRoles = new ArrayMap<>();
+
+ // Cache for applied roles for capture presets and devices. The cache avoids reapplying the
+ // same list of devices for a given role and capture preset and the corresponding systematic
+ // redundant work in audio policy manager and audio flinger.
+ // The key is the pair <Preset , Role> and the value is the current list of devices.
+ private final ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>>
+ mAppliedPresetRoles = new ArrayMap<>();
+
+ interface AudioSystemInterface {
+ int deviceRoleAction(int usecase, int role, @Nullable List<AudioDeviceAttributes> devices);
+ }
+
+ private int addDevicesRole(
+ ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap,
+ AudioSystemInterface asi,
+ int useCase, int role, @NonNull List<AudioDeviceAttributes> devices) {
+ synchronized (rolesMap) {
+ Pair<Integer, Integer> key = new Pair<>(useCase, role);
+ List<AudioDeviceAttributes> roleDevices = new ArrayList<>();
+ List<AudioDeviceAttributes> appliedDevices = new ArrayList<>();
+
+ if (rolesMap.containsKey(key)) {
+ roleDevices = rolesMap.get(key);
+ for (AudioDeviceAttributes device : devices) {
+ if (!roleDevices.contains(device)) {
+ appliedDevices.add(device);
+ }
+ }
+ } else {
+ appliedDevices.addAll(devices);
+ }
+ if (appliedDevices.isEmpty()) {
+ return AudioSystem.SUCCESS;
+ }
+ final int status = asi.deviceRoleAction(useCase, role, appliedDevices);
+ if (status == AudioSystem.SUCCESS) {
+ roleDevices.addAll(appliedDevices);
+ rolesMap.put(key, roleDevices);
+ }
+ return status;
+ }
+ }
+
+ private int removeDevicesRole(
+ ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap,
+ AudioSystemInterface asi,
+ int useCase, int role, @NonNull List<AudioDeviceAttributes> devices) {
+ synchronized (rolesMap) {
+ Pair<Integer, Integer> key = new Pair<>(useCase, role);
+ if (!rolesMap.containsKey(key)) {
+ return AudioSystem.SUCCESS;
+ }
+ List<AudioDeviceAttributes> roleDevices = rolesMap.get(key);
+ List<AudioDeviceAttributes> appliedDevices = new ArrayList<>();
+ for (AudioDeviceAttributes device : devices) {
+ if (roleDevices.contains(device)) {
+ appliedDevices.add(device);
+ }
+ }
+ if (appliedDevices.isEmpty()) {
+ return AudioSystem.SUCCESS;
+ }
+ final int status = asi.deviceRoleAction(useCase, role, appliedDevices);
+ if (status == AudioSystem.SUCCESS) {
+ roleDevices.removeAll(appliedDevices);
+ if (roleDevices.isEmpty()) {
+ rolesMap.remove(key);
+ } else {
+ rolesMap.put(key, roleDevices);
+ }
+ }
+ return status;
+ }
+ }
+
+ private int setDevicesRole(
+ ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap,
+ AudioSystemInterface addOp,
+ AudioSystemInterface clearOp,
+ int useCase, int role, @NonNull List<AudioDeviceAttributes> devices) {
+ synchronized (rolesMap) {
+ Pair<Integer, Integer> key = new Pair<>(useCase, role);
+ List<AudioDeviceAttributes> roleDevices = new ArrayList<>();
+ List<AudioDeviceAttributes> appliedDevices = new ArrayList<>();
+
+ if (rolesMap.containsKey(key)) {
+ roleDevices = rolesMap.get(key);
+ boolean equal = false;
+ if (roleDevices.size() == devices.size()) {
+ roleDevices.retainAll(devices);
+ equal = roleDevices.size() == devices.size();
+ }
+ if (!equal) {
+ clearOp.deviceRoleAction(useCase, role, null);
+ roleDevices.clear();
+ appliedDevices.addAll(devices);
+ }
+ } else {
+ appliedDevices.addAll(devices);
+ }
+ if (appliedDevices.isEmpty()) {
+ return AudioSystem.SUCCESS;
+ }
+ final int status = addOp.deviceRoleAction(useCase, role, appliedDevices);
+ if (status == AudioSystem.SUCCESS) {
+ roleDevices.addAll(appliedDevices);
+ rolesMap.put(key, roleDevices);
+ }
+ return status;
+ }
+ }
+
+ private int clearDevicesRole(
+ ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap,
+ AudioSystemInterface asi, int useCase, int role) {
+ synchronized (rolesMap) {
+ Pair<Integer, Integer> key = new Pair<>(useCase, role);
+ if (!rolesMap.containsKey(key)) {
+ return AudioSystem.SUCCESS;
+ }
+ final int status = asi.deviceRoleAction(useCase, role, null);
+ if (status == AudioSystem.SUCCESS) {
+ rolesMap.remove(key);
+ }
+ return status;
+ }
+ }
+
+ @GuardedBy("mDevicesLock")
+ private void purgeDevicesRoles_l() {
+ purgeRoles(mAppliedStrategyRoles, (s, r, d) -> {
+ return mAudioSystem.removeDevicesRoleForStrategy(s, r, d); });
+ purgeRoles(mAppliedPresetRoles, (p, r, d) -> {
+ return mAudioSystem.removeDevicesRoleForCapturePreset(p, r, d); });
+ }
+
+ @GuardedBy("mDevicesLock")
+ private void purgeRoles(
+ ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap,
+ AudioSystemInterface asi) {
+ synchronized (rolesMap) {
+ Iterator<Map.Entry<Pair<Integer, Integer>, List<AudioDeviceAttributes>>> itRole =
+ rolesMap.entrySet().iterator();
+ while (itRole.hasNext()) {
+ Map.Entry<Pair<Integer, Integer>, List<AudioDeviceAttributes>> entry =
+ itRole.next();
+ Pair<Integer, Integer> keyRole = entry.getKey();
+ Iterator<AudioDeviceAttributes> itDev = rolesMap.get(keyRole).iterator();
+ while (itDev.hasNext()) {
+ AudioDeviceAttributes ada = itDev.next();
+ final String devKey = DeviceInfo.makeDeviceListKey(ada.getInternalType(),
+ ada.getAddress());
+ if (mConnectedDevices.get(devKey) == null) {
+ asi.deviceRoleAction(keyRole.first, keyRole.second, Arrays.asList(ada));
+ itDev.remove();
+ }
+ }
+ if (rolesMap.get(keyRole).isEmpty()) {
+ itRole.remove();
+ }
+ }
+ }
+ }
+
+//-----------------------------------------------------------------------
/**
* Check if a device is in the list of connected devices
@@ -871,10 +1167,11 @@ public class AudioDeviceInventory {
* @param connect true if connection
* @param isForTesting if true, not calling AudioSystem for the connection as this is
* just for testing
+ * @param btDevice the corresponding Bluetooth device when relevant.
* @return false if an error was reported by AudioSystem
*/
/*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,
- boolean isForTesting) {
+ boolean isForTesting, @Nullable BluetoothDevice btDevice) {
int device = attributes.getInternalType();
String address = attributes.getAddress();
String deviceName = attributes.getName();
@@ -889,6 +1186,7 @@ public class AudioDeviceInventory {
.set(MediaMetrics.Property.MODE, connect
? MediaMetrics.Value.CONNECT : MediaMetrics.Value.DISCONNECT)
.set(MediaMetrics.Property.NAME, deviceName);
+ boolean status = false;
synchronized (mDevicesLock) {
final String deviceKey = DeviceInfo.makeDeviceListKey(device, address);
if (AudioService.DEBUG_DEVICES) {
@@ -916,24 +1214,31 @@ public class AudioDeviceInventory {
.record();
return false;
}
- mConnectedDevices.put(deviceKey, new DeviceInfo(
- device, deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
+ mConnectedDevices.put(deviceKey, new DeviceInfo(device, deviceName, address));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
- mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
- return true;
+ status = true;
} else if (!connect && isConnected) {
mAudioSystem.setDeviceConnectionState(attributes,
AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
+ status = true;
+ }
+ if (status) {
+ if (AudioSystem.isBluetoothScoDevice(device)) {
+ updateBluetoothPreferredModes_l(connect ? btDevice : null /*connectedDevice*/);
+ if (!connect) {
+ purgeDevicesRoles_l();
+ }
+ }
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
- return true;
+ } else {
+ Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey
+ + ", deviceSpec=" + di + ", connect=" + connect);
+ mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED).record();
}
- Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey
- + ", deviceSpec=" + di + ", connect=" + connect);
}
- mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED).record();
- return false;
+ return status;
}
@@ -1142,15 +1447,20 @@ public class AudioDeviceInventory {
// Internal utilities
@GuardedBy("mDevicesLock")
- private void makeA2dpDeviceAvailable(String address, String name, String eventSource,
- int a2dpCodec) {
+ private void makeA2dpDeviceAvailable(AudioDeviceBroker.BtDeviceInfo btInfo,
+ String eventSource) {
+ final String address = btInfo.mDevice.getAddress();
+ final String name = BtHelper.getName(btInfo.mDevice);
+ final int a2dpCodec = btInfo.mCodec;
+
// enable A2DP before notifying A2DP connection to avoid unnecessary processing in
// audio policy manager
mDeviceBroker.setBluetoothA2dpOnInt(true, true /*fromA2dp*/, eventSource);
// at this point there could be another A2DP device already connected in APM, but it
// doesn't matter as this new one will overwrite the previous one
- final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name),
+ AudioDeviceAttributes ada = new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name);
+ final int res = mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec);
// TODO: log in MediaMetrics once distinction between connection failure and
@@ -1172,8 +1482,7 @@ public class AudioDeviceInventory {
// The convention for head tracking sensors associated with A2DP devices is to
// use a UUID derived from the MAC address as follows:
// time_low = 0, time_mid = 0, time_hi = 0, clock_seq = 0, node = MAC Address
- UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(
- new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
+ UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
final DeviceInfo di = new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
address, a2dpCodec, sensorUuid);
final String diKey = di.getKey();
@@ -1184,6 +1493,208 @@ public class AudioDeviceInventory {
mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
setCurrentAudioRouteNameIfPossible(name, true /*fromA2dp*/);
+
+ updateBluetoothPreferredModes_l(btInfo.mDevice /*connectedDevice*/);
+ }
+
+ static final int[] CAPTURE_PRESETS = new int[] {AudioSource.MIC, AudioSource.CAMCORDER,
+ AudioSource.VOICE_RECOGNITION, AudioSource.VOICE_COMMUNICATION,
+ AudioSource.UNPROCESSED, AudioSource.VOICE_PERFORMANCE, AudioSource.HOTWORD};
+
+ // reflects system property persist.bluetooth.enable_dual_mode_audio
+ final boolean mBluetoothDualModeEnabled;
+ /**
+ * Goes over all connected Bluetooth devices and set the audio policy device role to DISABLED
+ * or not according to their own and other devices modes.
+ * The top priority is given to LE devices, then SCO ,then A2DP.
+ */
+ @GuardedBy("mDevicesLock")
+ private void applyConnectedDevicesRoles_l() {
+ if (!mBluetoothDualModeEnabled) {
+ return;
+ }
+ DeviceInfo leOutDevice =
+ getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
+ DeviceInfo leInDevice =
+ getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_BLE_SET);
+ DeviceInfo a2dpDevice =
+ getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+ DeviceInfo scoOutDevice =
+ getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_SCO_SET);
+ DeviceInfo scoInDevice =
+ getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_SCO_SET);
+ boolean disableA2dp = (leOutDevice != null && leOutDevice.isOutputOnlyModeEnabled());
+ boolean disableSco = (leOutDevice != null && leOutDevice.isDuplexModeEnabled())
+ || (leInDevice != null && leInDevice.isDuplexModeEnabled());
+ AudioDeviceAttributes communicationDevice =
+ mDeviceBroker.mActiveCommunicationDevice == null
+ ? null : ((mDeviceBroker.isInCommunication()
+ && mDeviceBroker.mActiveCommunicationDevice != null)
+ ? new AudioDeviceAttributes(mDeviceBroker.mActiveCommunicationDevice)
+ : null);
+
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, "applyConnectedDevicesRoles_l\n - leOutDevice: " + leOutDevice
+ + "\n - leInDevice: " + leInDevice
+ + "\n - a2dpDevice: " + a2dpDevice
+ + "\n - scoOutDevice: " + scoOutDevice
+ + "\n - scoInDevice: " + scoInDevice
+ + "\n - disableA2dp: " + disableA2dp
+ + ", disableSco: " + disableSco);
+ }
+
+ for (DeviceInfo di : mConnectedDevices.values()) {
+ if (!AudioSystem.isBluetoothDevice(di.mDeviceType)) {
+ continue;
+ }
+ AudioDeviceAttributes ada =
+ new AudioDeviceAttributes(di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, " + checking Device: " + ada);
+ }
+ if (ada.equalTypeAddress(communicationDevice)) {
+ continue;
+ }
+
+ if (AudioSystem.isBluetoothOutDevice(di.mDeviceType)) {
+ for (AudioProductStrategy strategy : mStrategies) {
+ boolean disable = false;
+ if (strategy.getId() == mDeviceBroker.mCommunicationStrategyId) {
+ if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
+ disable = disableSco || !di.isDuplexModeEnabled();
+ } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) {
+ disable = !di.isDuplexModeEnabled();
+ }
+ } else {
+ if (AudioSystem.isBluetoothA2dpOutDevice(di.mDeviceType)) {
+ disable = disableA2dp || !di.isOutputOnlyModeEnabled();
+ } else if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
+ disable = disableSco || !di.isOutputOnlyModeEnabled();
+ } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) {
+ disable = !di.isOutputOnlyModeEnabled();
+ }
+ }
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, " - strategy: " + strategy.getId()
+ + ", disable: " + disable);
+ }
+ if (disable) {
+ addDevicesRoleForStrategy(strategy.getId(),
+ AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
+ } else {
+ removeDevicesRoleForStrategy(strategy.getId(),
+ AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
+ }
+ }
+ }
+ if (AudioSystem.isBluetoothInDevice(di.mDeviceType)) {
+ for (int capturePreset : CAPTURE_PRESETS) {
+ boolean disable = false;
+ if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
+ disable = disableSco || !di.isDuplexModeEnabled();
+ } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) {
+ disable = !di.isDuplexModeEnabled();
+ }
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, " - capturePreset: " + capturePreset
+ + ", disable: " + disable);
+ }
+ if (disable) {
+ addDevicesRoleForCapturePreset(capturePreset,
+ AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
+ } else {
+ removeDevicesRoleForCapturePreset(capturePreset,
+ AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
+ }
+ }
+ }
+ }
+ }
+
+ /* package */ void applyConnectedDevicesRoles() {
+ synchronized (mDevicesLock) {
+ applyConnectedDevicesRoles_l();
+ }
+ }
+
+ @GuardedBy("mDevicesLock")
+ int checkProfileIsConnected(int profile) {
+ switch (profile) {
+ case BluetoothProfile.HEADSET:
+ if (getFirstConnectedDeviceOfTypes(
+ AudioSystem.DEVICE_OUT_ALL_SCO_SET) != null
+ || getFirstConnectedDeviceOfTypes(
+ AudioSystem.DEVICE_IN_ALL_SCO_SET) != null) {
+ return profile;
+ }
+ break;
+ case BluetoothProfile.A2DP:
+ if (getFirstConnectedDeviceOfTypes(
+ AudioSystem.DEVICE_OUT_ALL_A2DP_SET) != null) {
+ return profile;
+ }
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ if (getFirstConnectedDeviceOfTypes(
+ AudioSystem.DEVICE_OUT_ALL_BLE_SET) != null
+ || getFirstConnectedDeviceOfTypes(
+ AudioSystem.DEVICE_IN_ALL_BLE_SET) != null) {
+ return profile;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+ }
+
+ @GuardedBy("mDevicesLock")
+ private void updateBluetoothPreferredModes_l(BluetoothDevice connectedDevice) {
+ if (!mBluetoothDualModeEnabled) {
+ return;
+ }
+ HashSet<String> processedAddresses = new HashSet<>(0);
+ for (DeviceInfo di : mConnectedDevices.values()) {
+ if (!AudioSystem.isBluetoothDevice(di.mDeviceType)
+ || processedAddresses.contains(di.mDeviceAddress)) {
+ continue;
+ }
+ Bundle preferredProfiles = BtHelper.getPreferredAudioProfiles(di.mDeviceAddress);
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, "updateBluetoothPreferredModes_l processing device address: "
+ + di.mDeviceAddress + ", preferredProfiles: " + preferredProfiles);
+ }
+ for (DeviceInfo di2 : mConnectedDevices.values()) {
+ if (!AudioSystem.isBluetoothDevice(di2.mDeviceType)
+ || !di.mDeviceAddress.equals(di2.mDeviceAddress)) {
+ continue;
+ }
+ int profile = BtHelper.getProfileFromType(di2.mDeviceType);
+ if (profile == 0) {
+ continue;
+ }
+ int preferredProfile = checkProfileIsConnected(
+ preferredProfiles.getInt(BluetoothAdapter.AUDIO_MODE_DUPLEX));
+ if (preferredProfile == profile || preferredProfile == 0) {
+ di2.setModeEnabled(BluetoothAdapter.AUDIO_MODE_DUPLEX);
+ } else {
+ di2.setModeDisabled(BluetoothAdapter.AUDIO_MODE_DUPLEX);
+ }
+ preferredProfile = checkProfileIsConnected(
+ preferredProfiles.getInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY));
+ if (preferredProfile == profile || preferredProfile == 0) {
+ di2.setModeEnabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
+ } else {
+ di2.setModeDisabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
+ }
+ }
+ processedAddresses.add(di.mDeviceAddress);
+ }
+ applyConnectedDevicesRoles_l();
+ if (connectedDevice != null) {
+ mDeviceBroker.postNotifyPreferredAudioProfileApplied(connectedDevice);
+ }
}
@GuardedBy("mDevicesLock")
@@ -1231,6 +1742,8 @@ public class AudioDeviceInventory {
// Remove A2DP routes as well
setCurrentAudioRouteNameIfPossible(null, true /*fromA2dp*/);
mmi.record();
+ updateBluetoothPreferredModes_l(null /*connectedDevice*/);
+ purgeDevicesRoles_l();
}
@GuardedBy("mDevicesLock")
@@ -1260,8 +1773,7 @@ public class AudioDeviceInventory {
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
- new DeviceInfo(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
- address, AudioSystem.AUDIO_FORMAT_DEFAULT));
+ new DeviceInfo(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "", address));
}
@GuardedBy("mDevicesLock")
@@ -1287,8 +1799,7 @@ public class AudioDeviceInventory {
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
- new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name,
- address, AudioSystem.AUDIO_FORMAT_DEFAULT));
+ new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name, address));
mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_HEARING_AID);
mDeviceBroker.postApplyVolumeOnDevice(streamType,
AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
@@ -1326,29 +1837,56 @@ public class AudioDeviceInventory {
* @return true if a DEVICE_OUT_HEARING_AID is connected, false otherwise.
*/
boolean isHearingAidConnected() {
+ return getFirstConnectedDeviceOfTypes(
+ Sets.newHashSet(AudioSystem.DEVICE_OUT_HEARING_AID)) != null;
+ }
+
+ /**
+ * Returns a DeviceInfo for the first connected device matching one of the supplied types
+ */
+ private DeviceInfo getFirstConnectedDeviceOfTypes(Set<Integer> internalTypes) {
+ List<DeviceInfo> devices = getConnectedDevicesOfTypes(internalTypes);
+ return devices.isEmpty() ? null : devices.get(0);
+ }
+
+ /**
+ * Returns a list of connected devices matching one of the supplied types
+ */
+ private List<DeviceInfo> getConnectedDevicesOfTypes(Set<Integer> internalTypes) {
+ ArrayList<DeviceInfo> devices = new ArrayList<>();
synchronized (mDevicesLock) {
for (DeviceInfo di : mConnectedDevices.values()) {
- if (di.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
- return true;
+ if (internalTypes.contains(di.mDeviceType)) {
+ devices.add(di);
}
}
- return false;
}
+ return devices;
+ }
+
+ /* package */ AudioDeviceAttributes getDeviceOfType(int type) {
+ DeviceInfo di = getFirstConnectedDeviceOfTypes(Sets.newHashSet(type));
+ return di == null ? null : new AudioDeviceAttributes(
+ di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
}
@GuardedBy("mDevicesLock")
- private void makeLeAudioDeviceAvailable(String address, String name, int streamType,
- int volumeIndex, int device, String eventSource) {
+ private void makeLeAudioDeviceAvailable(
+ AudioDeviceBroker.BtDeviceInfo btInfo, int streamType, String eventSource) {
+ final String address = btInfo.mDevice.getAddress();
+ final String name = BtHelper.getName(btInfo.mDevice);
+ final int volumeIndex = btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10;
+ final int device = btInfo.mAudioSystemDevice;
+
if (device != AudioSystem.DEVICE_NONE) {
/* Audio Policy sees Le Audio similar to A2DP. Let's make sure
* AUDIO_POLICY_FORCE_NO_BT_A2DP is not set
*/
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
- final int res = AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
- device, address, name),
- AudioSystem.DEVICE_STATE_AVAILABLE,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioDeviceAttributes ada = new AudioDeviceAttributes(device, address, name);
+ final int res = AudioSystem.setDeviceConnectionState(ada,
+ AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"APM failed to make available LE Audio device addr=" + address
@@ -1359,12 +1897,13 @@ public class AudioDeviceInventory {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"LE Audio device addr=" + address + " now available").printLog(TAG));
}
-
// Reset LEA suspend state each time a new sink is connected
mDeviceBroker.clearLeAudioSuspended();
+ UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
- new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
+ new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT,
+ sensorUuid));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false);
}
@@ -1380,6 +1919,8 @@ public class AudioDeviceInventory {
final int maxIndex = mDeviceBroker.getMaxVssVolumeForStream(streamType);
mDeviceBroker.postSetLeAudioVolumeIndex(leAudioVolIndex, maxIndex, streamType);
mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "makeLeAudioDeviceAvailable");
+
+ updateBluetoothPreferredModes_l(btInfo.mDevice /*connectedDevice*/);
}
@GuardedBy("mDevicesLock")
@@ -1404,6 +1945,8 @@ public class AudioDeviceInventory {
}
setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/);
+ updateBluetoothPreferredModes_l(null /*connectedDevice*/);
+ purgeDevicesRoles_l();
}
@GuardedBy("mDevicesLock")
@@ -1739,18 +2282,6 @@ public class AudioDeviceInventory {
}
}
- /* package */ AudioDeviceAttributes getDeviceOfType(int type) {
- synchronized (mDevicesLock) {
- for (DeviceInfo di : mConnectedDevices.values()) {
- if (di.mDeviceType == type) {
- return new AudioDeviceAttributes(
- di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
- }
- }
- }
- return null;
- }
-
//----------------------------------------------------------
// For tests only
@@ -1761,10 +2292,12 @@ public class AudioDeviceInventory {
*/
@VisibleForTesting
public boolean isA2dpDeviceConnected(@NonNull BluetoothDevice device) {
- final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- device.getAddress());
- synchronized (mDevicesLock) {
- return (mConnectedDevices.get(key) != null);
+ for (DeviceInfo di : getConnectedDevicesOfTypes(
+ Sets.newHashSet(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP))) {
+ if (di.mDeviceAddress.equals(device.getAddress())) {
+ return true;
+ }
}
+ return false;
}
}
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index d066340c42b2..43438942a060 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -445,7 +445,7 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback,
}
/**
- * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int, int[], String[])}
+ * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int, List)}
* @param capturePreset
* @param role
* @param devicesToRemove
@@ -458,6 +458,19 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback,
}
/**
+ * Same as {@link AudioSystem#addDevicesRoleForCapturePreset(int, int, List)}
+ * @param capturePreset the capture preset to configure
+ * @param role the role of the devices
+ * @param devices the list of devices to be added as role for the given capture preset
+ * @return {@link #SUCCESS} if successfully added
+ */
+ public int addDevicesRoleForCapturePreset(
+ int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
+ invalidateRoutingCache();
+ return AudioSystem.addDevicesRoleForCapturePreset(capturePreset, role, devices);
+ }
+
+ /**
* Same as {@link AudioSystem#}
* @param capturePreset
* @param role
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 8c27c3ecfd87..e46c3cc4a285 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -33,6 +33,7 @@ import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.BluetoothProfileConnectionInfo;
import android.os.Binder;
+import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -150,60 +151,12 @@ public class BtHelper {
}
}
- //----------------------------------------------------------------------
- /*package*/ static class BluetoothA2dpDeviceInfo {
- private final @NonNull BluetoothDevice mBtDevice;
- private final int mVolume;
- private final @AudioSystem.AudioFormatNativeEnumForBtCodec int mCodec;
-
- BluetoothA2dpDeviceInfo(@NonNull BluetoothDevice btDevice) {
- this(btDevice, -1, AudioSystem.AUDIO_FORMAT_DEFAULT);
- }
-
- BluetoothA2dpDeviceInfo(@NonNull BluetoothDevice btDevice, int volume, int codec) {
- mBtDevice = btDevice;
- mVolume = volume;
- mCodec = codec;
- }
-
- public @NonNull BluetoothDevice getBtDevice() {
- return mBtDevice;
- }
-
- public int getVolume() {
- return mVolume;
- }
-
- public @AudioSystem.AudioFormatNativeEnumForBtCodec int getCodec() {
- return mCodec;
- }
-
- // redefine equality op so we can match messages intended for this device
- @Override
- public boolean equals(Object o) {
- if (o == null) {
- return false;
- }
- if (this == o) {
- return true;
- }
- if (o instanceof BluetoothA2dpDeviceInfo) {
- return mBtDevice.equals(((BluetoothA2dpDeviceInfo) o).getBtDevice());
- }
- return false;
- }
-
-
- }
-
// A2DP device events
/*package*/ static final int EVENT_DEVICE_CONFIG_CHANGE = 0;
- /*package*/ static final int EVENT_ACTIVE_DEVICE_CHANGE = 1;
- /*package*/ static String a2dpDeviceEventToString(int event) {
+ /*package*/ static String deviceEventToString(int event) {
switch (event) {
case EVENT_DEVICE_CONFIG_CHANGE: return "DEVICE_CONFIG_CHANGE";
- case EVENT_ACTIVE_DEVICE_CHANGE: return "ACTIVE_DEVICE_CHANGE";
default:
return new String("invalid event:" + event);
}
@@ -620,11 +573,12 @@ public class BtHelper {
return btHeadsetDeviceToAudioDevice(mBluetoothHeadsetDevice);
}
- private AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) {
+ private static AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) {
if (btDevice == null) {
return new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
}
String address = btDevice.getAddress();
+ String name = getName(btDevice);
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
@@ -646,7 +600,7 @@ public class BtHelper {
+ " btClass: " + (btClass == null ? "Unknown" : btClass)
+ " nativeType: " + nativeType + " address: " + address);
}
- return new AudioDeviceAttributes(nativeType, address);
+ return new AudioDeviceAttributes(nativeType, address, name);
}
private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
@@ -655,12 +609,9 @@ public class BtHelper {
}
int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
AudioDeviceAttributes audioDevice = btHeadsetDeviceToAudioDevice(btDevice);
- String btDeviceName = getName(btDevice);
boolean result = false;
if (isActive) {
- result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
- audioDevice.getInternalType(), audioDevice.getAddress(), btDeviceName),
- isActive);
+ result |= mDeviceBroker.handleDeviceConnection(audioDevice, isActive, btDevice);
} else {
int[] outDeviceTypes = {
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
@@ -669,14 +620,14 @@ public class BtHelper {
};
for (int outDeviceType : outDeviceTypes) {
result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
- outDeviceType, audioDevice.getAddress(), btDeviceName),
- isActive);
+ outDeviceType, audioDevice.getAddress(), audioDevice.getName()),
+ isActive, btDevice);
}
}
// handleDeviceConnection() && result to make sure the method get executed
result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
- inDevice, audioDevice.getAddress(), btDeviceName),
- isActive) && result;
+ inDevice, audioDevice.getAddress(), audioDevice.getName()),
+ isActive, btDevice) && result;
return result;
}
@@ -973,6 +924,30 @@ public class BtHelper {
}
}
+ /*package */ static int getProfileFromType(int deviceType) {
+ if (AudioSystem.isBluetoothA2dpOutDevice(deviceType)) {
+ return BluetoothProfile.A2DP;
+ } else if (AudioSystem.isBluetoothScoDevice(deviceType)) {
+ return BluetoothProfile.HEADSET;
+ } else if (AudioSystem.isBluetoothLeDevice(deviceType)) {
+ return BluetoothProfile.LE_AUDIO;
+ }
+ return 0; // 0 is not a valid profile
+ }
+
+ /*package */ static Bundle getPreferredAudioProfiles(String address) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ return adapter.getPreferredAudioProfiles(adapter.getRemoteDevice(address));
+ }
+
+ /**
+ * Notifies Bluetooth framework that new preferred audio profiles for Bluetooth devices
+ * have been applied.
+ */
+ public static void onNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) {
+ BluetoothAdapter.getDefaultAdapter().notifyActiveDeviceChangeApplied(btDevice);
+ }
+
/**
* Returns the string equivalent for the btDeviceClass class.
*/
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 9429b4c129f5..4984f125b00f 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -303,8 +303,6 @@ public class SoundDoseHelper {
SAFE_MEDIA_VOLUME_UNINITIALIZED);
mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLE_BROADCAST,
SAFE_MEDIA_VOLUME_UNINITIALIZED);
- mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_HEARING_AID,
- SAFE_MEDIA_VOLUME_UNINITIALIZED);
mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
SAFE_MEDIA_VOLUME_UNINITIALIZED);
// TODO(b/278265907): enable A2DP when we can distinguish A2DP headsets
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorList.java b/services/core/java/com/android/server/biometrics/sensors/SensorList.java
new file mode 100644
index 000000000000..1cff92fba31d
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorList.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors;
+
+import android.app.IActivityManager;
+import android.app.SynchronousUserSwitchObserver;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseArray;
+
+/**
+ * Keep track of the sensors that is supported by the HAL.
+ * @param <T> T is either face sensor or fingerprint sensor.
+ */
+public class SensorList<T> {
+ private static final String TAG = "SensorList";
+ private final SparseArray<T> mSensors;
+ private final IActivityManager mActivityManager;
+
+ public SensorList(IActivityManager activityManager) {
+ mSensors = new SparseArray<T>();
+ mActivityManager = activityManager;
+ }
+
+ /**
+ * Adding sensor to the map with the sensor id as key. Also, starts a session if the user Id is
+ * NULL.
+ */
+ public void addSensor(int sensorId, T sensor, int sessionUserId,
+ SynchronousUserSwitchObserver userSwitchObserver) {
+ mSensors.put(sensorId, sensor);
+ registerUserSwitchObserver(sessionUserId, userSwitchObserver);
+ }
+
+ private void registerUserSwitchObserver(int sessionUserId,
+ SynchronousUserSwitchObserver userSwitchObserver) {
+ try {
+ mActivityManager.registerUserSwitchObserver(userSwitchObserver,
+ TAG);
+ if (sessionUserId == UserHandle.USER_NULL) {
+ userSwitchObserver.onUserSwitching(UserHandle.USER_SYSTEM);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to register user switch observer");
+ }
+ }
+
+ /**
+ * Returns the sensor corresponding to the key at a specific position.
+ */
+ public T valueAt(int position) {
+ return mSensors.valueAt(position);
+ }
+
+ /**
+ * Returns the sensor associated with sensorId as key.
+ */
+ public T get(int sensorId) {
+ return mSensors.get(sensorId);
+ }
+
+ /**
+ * Returns the sensorId at the specified position.
+ */
+ public int keyAt(int position) {
+ return mSensors.keyAt(position);
+ }
+
+ /**
+ * Returns the number of sensors added.
+ */
+ public int size() {
+ return mSensors.size();
+ }
+
+ /**
+ * Returns true if a sensor exists for the specified sensorId.
+ */
+ public boolean contains(int sensorId) {
+ return mSensors.contains(sensorId);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index c5037b7012f2..a50164718417 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.app.SynchronousUserSwitchObserver;
import android.app.TaskStackListener;
import android.content.Context;
import android.content.pm.UserInfo;
@@ -41,9 +42,9 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Surface;
@@ -62,6 +63,7 @@ import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.InvalidationRequesterClient;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.PerformanceTracker;
+import com.android.server.biometrics.sensors.SensorList;
import com.android.server.biometrics.sensors.face.FaceUtils;
import com.android.server.biometrics.sensors.face.ServiceProvider;
import com.android.server.biometrics.sensors.face.UsageStats;
@@ -86,7 +88,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@NonNull
@VisibleForTesting
- final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
+ final SensorList<Sensor> mFaceSensors;
@NonNull
private final Context mContext;
@NonNull
@@ -117,8 +119,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public void onTaskStackChanged() {
mHandler.post(() -> {
- for (int i = 0; i < mSensors.size(); i++) {
- final BaseClientMonitor client = mSensors.valueAt(i).getScheduler()
+ for (int i = 0; i < mFaceSensors.size(); i++) {
+ final BaseClientMonitor client = mFaceSensors.valueAt(i).getScheduler()
.getCurrentClient();
if (!(client instanceof AuthenticationClient)) {
Slog.e(getTag(), "Task stack changed for client: " + client);
@@ -133,7 +135,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
&& !client.isAlreadyDone()) {
Slog.e(getTag(), "Stopping background authentication,"
+ " currentClient: " + client);
- mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
+ mFaceSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
client.getToken(), client.getRequestId());
}
}
@@ -150,7 +152,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
mHalInstanceName = halInstanceName;
- mSensors = new SparseArray<>();
+ mFaceSensors = new SensorList<>(ActivityManager.getService());
mHandler = new Handler(Looper.getMainLooper());
mUsageStats = new UsageStats(context);
mLockoutResetDispatcher = lockoutResetDispatcher;
@@ -178,8 +180,15 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
false /* resetLockoutRequiresChallenge */);
final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
internalProp, lockoutResetDispatcher, mBiometricContext);
-
- mSensors.put(sensorId, sensor);
+ final int userId = sensor.getLazySession().get() == null ? UserHandle.USER_NULL :
+ sensor.getLazySession().get().getUserId();
+ mFaceSensors.addSensor(sensorId, sensor, userId,
+ new SynchronousUserSwitchObserver() {
+ @Override
+ public void onUserSwitching(int newUserId) {
+ scheduleInternalCleanup(sensorId, newUserId, null /* callback */);
+ }
+ });
Slog.d(getTag(), "Added: " + internalProp);
}
}
@@ -223,8 +232,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
Slog.e(getTag(), "Unable to linkToDeath", e);
}
- for (int i = 0; i < mSensors.size(); i++) {
- final int sensorId = mSensors.keyAt(i);
+ for (int i = 0; i < mFaceSensors.size(); i++) {
+ final int sensorId = mFaceSensors.keyAt(i);
scheduleLoadAuthenticatorIds(sensorId);
scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(),
null /* callback */);
@@ -234,20 +243,20 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
}
private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor client) {
- if (!mSensors.contains(sensorId)) {
+ if (!mFaceSensors.contains(sensorId)) {
throw new IllegalStateException("Unable to schedule client: " + client
+ " for sensor: " + sensorId);
}
- mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ mFaceSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
}
private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor client,
ClientMonitorCallback callback) {
- if (!mSensors.contains(sensorId)) {
+ if (!mFaceSensors.contains(sensorId)) {
throw new IllegalStateException("Unable to schedule client: " + client
+ " for sensor: " + sensorId);
}
- mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
+ mFaceSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
}
private void scheduleLoadAuthenticatorIds(int sensorId) {
@@ -259,12 +268,12 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
private void scheduleLoadAuthenticatorIdsForUser(int sensorId, int userId) {
mHandler.post(() -> {
final FaceGetAuthenticatorIdClient client = new FaceGetAuthenticatorIdClient(
- mContext, mSensors.get(sensorId).getLazySession(), userId,
+ mContext, mFaceSensors.get(sensorId).getLazySession(), userId,
mContext.getOpPackageName(), sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
- mSensors.get(sensorId).getAuthenticatorIds());
+ mFaceSensors.get(sensorId).getAuthenticatorIds());
scheduleForSensor(sensorId, client);
});
@@ -283,15 +292,15 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public boolean containsSensor(int sensorId) {
- return mSensors.contains(sensorId);
+ return mFaceSensors.contains(sensorId);
}
@NonNull
@Override
public List<FaceSensorPropertiesInternal> getSensorProperties() {
final List<FaceSensorPropertiesInternal> props = new ArrayList<>();
- for (int i = 0; i < mSensors.size(); ++i) {
- props.add(mSensors.valueAt(i).getSensorProperties());
+ for (int i = 0; i < mFaceSensors.size(); ++i) {
+ props.add(mFaceSensors.valueAt(i).getSensorProperties());
}
return props;
}
@@ -299,7 +308,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@NonNull
@Override
public FaceSensorPropertiesInternal getSensorProperties(int sensorId) {
- return mSensors.get(sensorId).getSensorProperties();
+ return mFaceSensors.get(sensorId).getSensorProperties();
}
@NonNull
@@ -318,11 +327,11 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@NonNull IInvalidationCallback callback) {
mHandler.post(() -> {
final FaceInvalidationClient client = new FaceInvalidationClient(mContext,
- mSensors.get(sensorId).getLazySession(), userId, sensorId,
+ mFaceSensors.get(sensorId).getLazySession(), userId, sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
- mSensors.get(sensorId).getAuthenticatorIds(), callback);
+ mFaceSensors.get(sensorId).getAuthenticatorIds(), callback);
scheduleForSensor(sensorId, client);
});
}
@@ -335,7 +344,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public long getAuthenticatorId(int sensorId, int userId) {
- return mSensors.get(sensorId).getAuthenticatorIds().getOrDefault(userId, 0L);
+ return mFaceSensors.get(sensorId).getAuthenticatorIds().getOrDefault(userId, 0L);
}
@Override
@@ -348,7 +357,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@NonNull IFaceServiceReceiver receiver, String opPackageName) {
mHandler.post(() -> {
final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext,
- mSensors.get(sensorId).getLazySession(), token,
+ mFaceSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, opPackageName, sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
@@ -362,7 +371,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@NonNull String opPackageName, long challenge) {
mHandler.post(() -> {
final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
- mSensors.get(sensorId).getLazySession(), token, userId, opPackageName, sensorId,
+ mFaceSensors.get(sensorId).getLazySession(), token, userId,
+ opPackageName, sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext, challenge);
@@ -377,10 +387,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Nullable Surface previewSurface, boolean debugConsent) {
final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> {
- final int maxTemplatesPerUser = mSensors.get(
+ final int maxTemplatesPerUser = mFaceSensors.get(
sensorId).getSensorProperties().maxEnrollmentsPerUser;
final FaceEnrollClient client = new FaceEnrollClient(mContext,
- mSensors.get(sensorId).getLazySession(), token,
+ mFaceSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, id, FaceUtils.getInstance(sensorId), disabledFeatures,
ENROLL_TIMEOUT_SEC, previewSurface, sensorId,
@@ -406,7 +416,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public void cancelEnrollment(int sensorId, @NonNull IBinder token, long requestId) {
mHandler.post(() ->
- mSensors.get(sensorId).getScheduler().cancelEnrollment(token, requestId));
+ mFaceSensors.get(sensorId).getScheduler().cancelEnrollment(token, requestId));
}
@Override
@@ -419,7 +429,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceDetectClient client = new FaceDetectClient(mContext,
- mSensors.get(sensorId).getLazySession(),
+ mFaceSensors.get(sensorId).getLazySession(),
token, id, callback, options,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric);
@@ -431,7 +441,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) {
- mHandler.post(() -> mSensors.get(sensorId).getScheduler()
+ mHandler.post(() -> mFaceSensors.get(sensorId).getScheduler()
.cancelAuthenticationOrDetection(token, requestId));
}
@@ -446,12 +456,12 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
final int sensorId = options.getSensorId();
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(
- mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
- operationId, restricted, options, cookie,
+ mContext, mFaceSensors.get(sensorId).getLazySession(), token, requestId,
+ callback, operationId, restricted, options, cookie,
false /* requireConfirmation */,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric,
- mUsageStats, mSensors.get(sensorId).getLockoutCache(),
+ mUsageStats, mFaceSensors.get(sensorId).getLockoutCache(),
allowBackgroundAuthentication, Utils.getCurrentStrength(sensorId));
scheduleForSensor(sensorId, client, new ClientMonitorCallback() {
@Override
@@ -486,7 +496,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
- mHandler.post(() -> mSensors.get(sensorId).getScheduler()
+ mHandler.post(() -> mFaceSensors.get(sensorId).getScheduler()
.cancelAuthenticationOrDetection(token, requestId));
}
@@ -514,13 +524,13 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
mHandler.post(() -> {
final FaceRemovalClient client = new FaceRemovalClient(mContext,
- mSensors.get(sensorId).getLazySession(), token,
+ mFaceSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), faceIds, userId,
opPackageName, FaceUtils.getInstance(sensorId), sensorId,
createLogger(BiometricsProtoEnums.ACTION_REMOVE,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
- mSensors.get(sensorId).getAuthenticatorIds());
+ mFaceSensors.get(sensorId).getAuthenticatorIds());
scheduleForSensor(sensorId, client, mBiometricStateCallback);
});
}
@@ -529,12 +539,12 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
public void scheduleResetLockout(int sensorId, int userId, @NonNull byte[] hardwareAuthToken) {
mHandler.post(() -> {
final FaceResetLockoutClient client = new FaceResetLockoutClient(
- mContext, mSensors.get(sensorId).getLazySession(), userId,
+ mContext, mFaceSensors.get(sensorId).getLazySession(), userId,
mContext.getOpPackageName(), sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext, hardwareAuthToken,
- mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher,
+ mFaceSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher,
Utils.getCurrentStrength(sensorId));
scheduleForSensor(sensorId, client);
@@ -553,7 +563,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
return;
}
final FaceSetFeatureClient client = new FaceSetFeatureClient(mContext,
- mSensors.get(sensorId).getLazySession(), token,
+ mFaceSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId,
mContext.getOpPackageName(), sensorId,
BiometricLogger.ofUnknown(mContext), mBiometricContext,
@@ -573,7 +583,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
return;
}
final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext,
- mSensors.get(sensorId).getLazySession(), token, callback, userId,
+ mFaceSensors.get(sensorId).getLazySession(), token, callback, userId,
mContext.getOpPackageName(), sensorId, BiometricLogger.ofUnknown(mContext),
mBiometricContext);
scheduleForSensor(sensorId, client);
@@ -583,7 +593,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public void startPreparedClient(int sensorId, int cookie) {
mHandler.post(() -> {
- mSensors.get(sensorId).getScheduler().startPreparedClient(cookie);
+ mFaceSensors.get(sensorId).getScheduler().startPreparedClient(cookie);
});
}
@@ -599,13 +609,13 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
mHandler.post(() -> {
final FaceInternalCleanupClient client =
new FaceInternalCleanupClient(mContext,
- mSensors.get(sensorId).getLazySession(), userId,
+ mFaceSensors.get(sensorId).getLazySession(), userId,
mContext.getOpPackageName(), sensorId,
createLogger(BiometricsProtoEnums.ACTION_ENUMERATE,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
FaceUtils.getInstance(sensorId),
- mSensors.get(sensorId).getAuthenticatorIds());
+ mFaceSensors.get(sensorId).getAuthenticatorIds());
if (favorHalEnrollments) {
client.setFavorHalEnrollments();
}
@@ -622,8 +632,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
boolean clearSchedulerBuffer) {
- if (mSensors.contains(sensorId)) {
- mSensors.get(sensorId).dumpProtoState(sensorId, proto, clearSchedulerBuffer);
+ if (mFaceSensors.contains(sensorId)) {
+ mFaceSensors.get(sensorId).dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
}
@@ -672,7 +682,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
pw.println(mBiometricContext.getAuthSessionCoordinator());
pw.println("---AuthSessionCoordinator logs end ---");
- mSensors.get(sensorId).getScheduler().dump(pw);
+ mFaceSensors.get(sensorId).getScheduler().dump(pw);
mUsageStats.print(pw);
}
@@ -680,7 +690,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName) {
- return mSensors.get(sensorId).createTestSession(callback);
+ return mFaceSensors.get(sensorId).createTestSession(callback);
}
@Override
@@ -692,9 +702,9 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
Slog.e(getTag(), "HAL died");
mHandler.post(() -> {
mDaemon = null;
- for (int i = 0; i < mSensors.size(); i++) {
- final Sensor sensor = mSensors.valueAt(i);
- final int sensorId = mSensors.keyAt(i);
+ for (int i = 0; i < mFaceSensors.size(); i++) {
+ final Sensor sensor = mFaceSensors.valueAt(i);
+ final int sensorId = mFaceSensors.keyAt(i);
PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
sensor.onBinderDied();
}
@@ -708,7 +718,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public void scheduleWatchdog(int sensorId) {
Slog.d(getTag(), "Starting watchdog for face");
- final BiometricScheduler biometricScheduler = mSensors.get(sensorId).getScheduler();
+ final BiometricScheduler biometricScheduler = mFaceSensors.get(sensorId).getScheduler();
if (biometricScheduler == null) {
return;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 468bf5530d34..ffbf4e12f2ae 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -18,9 +18,6 @@ package com.android.server.biometrics.sensors.face.aidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.SynchronousUserSwitchObserver;
-import android.app.UserSwitchObserver;
import android.content.Context;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricsProtoEnums;
@@ -94,14 +91,6 @@ public class Sensor {
@NonNull private final Supplier<AidlSession> mLazySession;
@Nullable private AidlSession mCurrentSession;
- private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() {
- @Override
- public void onUserSwitching(int newUserId) {
- mProvider.scheduleInternalCleanup(
- mSensorProperties.sensorId, newUserId, null /* callback */);
- }
- };
-
@VisibleForTesting
public static class HalSessionCallback extends ISessionCallback.Stub {
/**
@@ -558,12 +547,6 @@ public class Sensor {
mLockoutCache = new LockoutCache();
mAuthenticatorIds = new HashMap<>();
mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
-
- try {
- ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, mTag);
- } catch (RemoteException e) {
- Slog.e(mTag, "Unable to register user switch observer");
- }
}
@NonNull Supplier<AidlSession> getLazySession() {
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 23b6f84e6954..58ece898a9fe 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
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.app.SynchronousUserSwitchObserver;
import android.app.TaskStackListener;
import android.content.Context;
import android.content.pm.UserInfo;
@@ -51,9 +52,9 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
@@ -71,6 +72,7 @@ import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.InvalidationRequesterClient;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.PerformanceTracker;
+import com.android.server.biometrics.sensors.SensorList;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.PowerPressHandler;
@@ -99,7 +101,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@NonNull
@VisibleForTesting
- final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
+ final SensorList<Sensor> mFingerprintSensors;
@NonNull
private final Context mContext;
@NonNull
@@ -127,8 +129,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void onTaskStackChanged() {
mHandler.post(() -> {
- for (int i = 0; i < mSensors.size(); i++) {
- final BaseClientMonitor client = mSensors.valueAt(i).getScheduler()
+ for (int i = 0; i < mFingerprintSensors.size(); i++) {
+ final BaseClientMonitor client = mFingerprintSensors.valueAt(i).getScheduler()
.getCurrentClient();
if (!(client instanceof AuthenticationClient)) {
Slog.e(getTag(), "Task stack changed for client: " + client);
@@ -143,8 +145,9 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
&& !client.isAlreadyDone()) {
Slog.e(getTag(), "Stopping background authentication,"
+ " currentClient: " + client);
- mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
- client.getToken(), client.getRequestId());
+ mFingerprintSensors.valueAt(i).getScheduler()
+ .cancelAuthenticationOrDetection(
+ client.getToken(), client.getRequestId());
}
}
});
@@ -160,7 +163,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mContext = context;
mBiometricStateCallback = biometricStateCallback;
mHalInstanceName = halInstanceName;
- mSensors = new SparseArray<>();
+ mFingerprintSensors = new SensorList<>(ActivityManager.getService());
mHandler = new Handler(Looper.getMainLooper());
mLockoutResetDispatcher = lockoutResetDispatcher;
mActivityTaskManager = ActivityTaskManager.getInstance();
@@ -201,8 +204,15 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
internalProp, lockoutResetDispatcher, gestureAvailabilityDispatcher,
mBiometricContext);
-
- mSensors.put(sensorId, sensor);
+ final int sessionUserId = sensor.getLazySession().get() == null ? UserHandle.USER_NULL :
+ sensor.getLazySession().get().getUserId();
+ mFingerprintSensors.addSensor(sensorId, sensor, sessionUserId,
+ new SynchronousUserSwitchObserver() {
+ @Override
+ public void onUserSwitching(int newUserId) {
+ scheduleInternalCleanup(sensorId, newUserId, null /* callback */);
+ }
+ });
Slog.d(getTag(), "Added: " + internalProp);
}
}
@@ -250,8 +260,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
Slog.e(getTag(), "Unable to linkToDeath", e);
}
- for (int i = 0; i < mSensors.size(); i++) {
- final int sensorId = mSensors.keyAt(i);
+ for (int i = 0; i < mFingerprintSensors.size(); i++) {
+ final int sensorId = mFingerprintSensors.keyAt(i);
scheduleLoadAuthenticatorIds(sensorId);
scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(),
null /* callback */);
@@ -261,33 +271,33 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
}
private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor client) {
- if (!mSensors.contains(sensorId)) {
+ if (!mFingerprintSensors.contains(sensorId)) {
throw new IllegalStateException("Unable to schedule client: " + client
+ " for sensor: " + sensorId);
}
- mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ mFingerprintSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
}
private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor client,
ClientMonitorCallback callback) {
- if (!mSensors.contains(sensorId)) {
+ if (!mFingerprintSensors.contains(sensorId)) {
throw new IllegalStateException("Unable to schedule client: " + client
+ " for sensor: " + sensorId);
}
- mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
+ mFingerprintSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
}
@Override
public boolean containsSensor(int sensorId) {
- return mSensors.contains(sensorId);
+ return mFingerprintSensors.contains(sensorId);
}
@NonNull
@Override
public List<FingerprintSensorPropertiesInternal> getSensorProperties() {
final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
- for (int i = 0; i < mSensors.size(); i++) {
- props.add(mSensors.valueAt(i).getSensorProperties());
+ for (int i = 0; i < mFingerprintSensors.size(); i++) {
+ props.add(mFingerprintSensors.valueAt(i).getSensorProperties());
}
return props;
}
@@ -295,12 +305,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Nullable
@Override
public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId) {
- if (mSensors.size() == 0) {
+ if (mFingerprintSensors.size() == 0) {
return null;
} else if (sensorId == SENSOR_ID_ANY) {
- return mSensors.valueAt(0).getSensorProperties();
+ return mFingerprintSensors.valueAt(0).getSensorProperties();
} else {
- final Sensor sensor = mSensors.get(sensorId);
+ final Sensor sensor = mFingerprintSensors.get(sensorId);
return sensor != null ? sensor.getSensorProperties() : null;
}
}
@@ -315,12 +325,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mHandler.post(() -> {
final FingerprintGetAuthenticatorIdClient client =
new FingerprintGetAuthenticatorIdClient(mContext,
- mSensors.get(sensorId).getLazySession(), userId,
+ mFingerprintSensors.get(sensorId).getLazySession(), userId,
mContext.getOpPackageName(), sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
- mSensors.get(sensorId).getAuthenticatorIds());
+ mFingerprintSensors.get(sensorId).getAuthenticatorIds());
scheduleForSensor(sensorId, client);
});
}
@@ -340,12 +350,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) {
mHandler.post(() -> {
final FingerprintResetLockoutClient client = new FingerprintResetLockoutClient(
- mContext, mSensors.get(sensorId).getLazySession(), userId,
+ mContext, mFingerprintSensors.get(sensorId).getLazySession(), userId,
mContext.getOpPackageName(), sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext, hardwareAuthToken,
- mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher,
+ mFingerprintSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher,
Utils.getCurrentStrength(sensorId));
scheduleForSensor(sensorId, client);
});
@@ -357,7 +367,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mHandler.post(() -> {
final FingerprintGenerateChallengeClient client =
new FingerprintGenerateChallengeClient(mContext,
- mSensors.get(sensorId).getLazySession(), token,
+ mFingerprintSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, opPackageName,
sensorId, createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
@@ -372,7 +382,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mHandler.post(() -> {
final FingerprintRevokeChallengeClient client =
new FingerprintRevokeChallengeClient(mContext,
- mSensors.get(sensorId).getLazySession(), token,
+ mFingerprintSensors.get(sensorId).getLazySession(), token,
userId, opPackageName, sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
@@ -388,16 +398,16 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@FingerprintManager.EnrollReason int enrollReason) {
final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> {
- final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties()
+ final int maxTemplatesPerUser = mFingerprintSensors.get(sensorId).getSensorProperties()
.maxEnrollmentsPerUser;
final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext,
- mSensors.get(sensorId).getLazySession(), token, id,
+ mFingerprintSensors.get(sensorId).getLazySession(), token, id,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
- mSensors.get(sensorId).getSensorProperties(),
+ mFingerprintSensors.get(sensorId).getSensorProperties(),
mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
maxTemplatesPerUser, enrollReason);
scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback(
@@ -419,7 +429,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void cancelEnrollment(int sensorId, @NonNull IBinder token, long requestId) {
mHandler.post(() ->
- mSensors.get(sensorId).getScheduler().cancelEnrollment(token, requestId));
+ mFingerprintSensors.get(sensorId).getScheduler()
+ .cancelEnrollment(token, requestId));
}
@Override
@@ -432,7 +443,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
final int sensorId = options.getSensorId();
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
- mSensors.get(sensorId).getLazySession(), token, id, callback,
+ mFingerprintSensors.get(sensorId).getLazySession(), token, id, callback,
options,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext,
@@ -454,15 +465,15 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
final int sensorId = options.getSensorId();
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
- mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
- operationId, restricted, options, cookie,
+ mContext, mFingerprintSensors.get(sensorId).getLazySession(), token, requestId,
+ callback, operationId, restricted, options, cookie,
false /* requireConfirmation */,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric,
- mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
+ mTaskStackListener, mFingerprintSensors.get(sensorId).getLockoutCache(),
mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
allowBackgroundAuthentication,
- mSensors.get(sensorId).getSensorProperties(), mHandler,
+ mFingerprintSensors.get(sensorId).getSensorProperties(), mHandler,
Utils.getCurrentStrength(sensorId),
SystemClock.elapsedRealtimeClock());
scheduleForSensor(sensorId, client, new ClientMonitorCallback() {
@@ -505,12 +516,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void startPreparedClient(int sensorId, int cookie) {
- mHandler.post(() -> mSensors.get(sensorId).getScheduler().startPreparedClient(cookie));
+ mHandler.post(() -> mFingerprintSensors.get(sensorId).getScheduler()
+ .startPreparedClient(cookie));
}
@Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
- mHandler.post(() -> mSensors.get(sensorId).getScheduler()
+ mHandler.post(() -> mFingerprintSensors.get(sensorId).getScheduler()
.cancelAuthenticationOrDetection(token, requestId));
}
@@ -541,13 +553,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@NonNull String opPackageName) {
mHandler.post(() -> {
final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext,
- mSensors.get(sensorId).getLazySession(), token,
+ mFingerprintSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), fingerprintIds, userId,
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
createLogger(BiometricsProtoEnums.ACTION_REMOVE,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
- mSensors.get(sensorId).getAuthenticatorIds());
+ mFingerprintSensors.get(sensorId).getAuthenticatorIds());
scheduleForSensor(sensorId, client, mBiometricStateCallback);
});
}
@@ -564,13 +576,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mHandler.post(() -> {
final FingerprintInternalCleanupClient client =
new FingerprintInternalCleanupClient(mContext,
- mSensors.get(sensorId).getLazySession(), userId,
+ mFingerprintSensors.get(sensorId).getLazySession(), userId,
mContext.getOpPackageName(), sensorId,
createLogger(BiometricsProtoEnums.ACTION_ENUMERATE,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
FingerprintUtils.getInstance(sensorId),
- mSensors.get(sensorId).getAuthenticatorIds());
+ mFingerprintSensors.get(sensorId).getAuthenticatorIds());
if (favorHalEnrollments) {
client.setFavorHalEnrollments();
}
@@ -612,11 +624,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mHandler.post(() -> {
final FingerprintInvalidationClient client =
new FingerprintInvalidationClient(mContext,
- mSensors.get(sensorId).getLazySession(), userId, sensorId,
+ mFingerprintSensors.get(sensorId).getLazySession(), userId, sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
- mSensors.get(sensorId).getAuthenticatorIds(), callback);
+ mFingerprintSensors.get(sensorId).getAuthenticatorIds(), callback);
scheduleForSensor(sensorId, client);
});
}
@@ -629,40 +641,43 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public long getAuthenticatorId(int sensorId, int userId) {
- return mSensors.get(sensorId).getAuthenticatorIds().getOrDefault(userId, 0L);
+ return mFingerprintSensors.get(sensorId).getAuthenticatorIds().getOrDefault(userId, 0L);
}
@Override
public void onPointerDown(long requestId, int sensorId, PointerContext pc) {
- mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId, (client) -> {
- if (!(client instanceof Udfps)) {
- Slog.e(getTag(), "onPointerDown received during client: " + client);
- return;
- }
- ((Udfps) client).onPointerDown(pc);
- });
+ mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(
+ requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(), "onPointerDown received during client: " + client);
+ return;
+ }
+ ((Udfps) client).onPointerDown(pc);
+ });
}
@Override
public void onPointerUp(long requestId, int sensorId, PointerContext pc) {
- mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId, (client) -> {
- if (!(client instanceof Udfps)) {
- Slog.e(getTag(), "onPointerUp received during client: " + client);
- return;
- }
- ((Udfps) client).onPointerUp(pc);
- });
+ mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(
+ requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(), "onPointerUp received during client: " + client);
+ return;
+ }
+ ((Udfps) client).onPointerUp(pc);
+ });
}
@Override
public void onUiReady(long requestId, int sensorId) {
- mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId, (client) -> {
- if (!(client instanceof Udfps)) {
- Slog.e(getTag(), "onUiReady received during client: " + client);
- return;
- }
- ((Udfps) client).onUiReady();
- });
+ mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(
+ requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(), "onUiReady received during client: " + client);
+ return;
+ }
+ ((Udfps) client).onUiReady();
+ });
}
@Override
@@ -672,8 +687,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void onPowerPressed() {
- for (int i = 0; i < mSensors.size(); i++) {
- final Sensor sensor = mSensors.valueAt(i);
+ for (int i = 0; i < mFingerprintSensors.size(); i++) {
+ final Sensor sensor = mFingerprintSensors.valueAt(i);
BaseClientMonitor client = sensor.getScheduler().getCurrentClient();
if (client == null) {
return;
@@ -698,8 +713,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
boolean clearSchedulerBuffer) {
- if (mSensors.contains(sensorId)) {
- mSensors.get(sensorId).dumpProtoState(sensorId, proto, clearSchedulerBuffer);
+ if (mFingerprintSensors.contains(sensorId)) {
+ mFingerprintSensors.get(sensorId).dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
}
@@ -748,14 +763,15 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
pw.println(mBiometricContext.getAuthSessionCoordinator());
pw.println("---AuthSessionCoordinator logs end ---");
- mSensors.get(sensorId).getScheduler().dump(pw);
+ mFingerprintSensors.get(sensorId).getScheduler().dump(pw);
}
@NonNull
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName) {
- return mSensors.get(sensorId).createTestSession(callback, mBiometricStateCallback);
+ return mFingerprintSensors.get(sensorId).createTestSession(callback,
+ mBiometricStateCallback);
}
@Override
@@ -764,9 +780,9 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mHandler.post(() -> {
mDaemon = null;
- for (int i = 0; i < mSensors.size(); i++) {
- final Sensor sensor = mSensors.valueAt(i);
- final int sensorId = mSensors.keyAt(i);
+ for (int i = 0; i < mFingerprintSensors.size(); i++) {
+ final Sensor sensor = mFingerprintSensors.valueAt(i);
+ final int sensorId = mFingerprintSensors.keyAt(i);
PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
sensor.onBinderDied();
}
@@ -821,7 +837,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void scheduleWatchdog(int sensorId) {
Slog.d(getTag(), "Starting watchdog for fingerprint");
- final BiometricScheduler biometricScheduler = mSensors.get(sensorId).getScheduler();
+ final BiometricScheduler biometricScheduler = mFingerprintSensors.get(sensorId)
+ .getScheduler();
if (biometricScheduler == null) {
return;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 22ca816ba56c..c0dde721b962 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -18,9 +18,6 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.SynchronousUserSwitchObserver;
-import android.app.UserSwitchObserver;
import android.content.Context;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricsProtoEnums;
@@ -96,14 +93,6 @@ public class Sensor {
@Nullable private AidlSession mCurrentSession;
@NonNull private final Supplier<AidlSession> mLazySession;
- private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() {
- @Override
- public void onUserSwitching(int newUserId) {
- mProvider.scheduleInternalCleanup(
- mSensorProperties.sensorId, newUserId, null /* callback */);
- }
- };
-
@VisibleForTesting
public static class HalSessionCallback extends ISessionCallback.Stub {
@@ -512,12 +501,6 @@ public class Sensor {
});
mAuthenticatorIds = new HashMap<>();
mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
-
- try {
- ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, mTag);
- } catch (RemoteException e) {
- Slog.e(mTag, "Unable to register user switch observer");
- }
}
@NonNull Supplier<AidlSession> getLazySession() {
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 1f82961efd22..6d4306198aa2 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -41,6 +41,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.RingBuffer;
@@ -278,6 +279,11 @@ public class NetdEventListenerService extends BaseNetdEventListener {
}
}
+ private boolean hasWifiTransport(Network network) {
+ final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
+ return nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
+ }
+
@Override
public synchronized void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader,
byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs) {
@@ -286,12 +292,21 @@ public class NetdEventListenerService extends BaseNetdEventListener {
throw new IllegalArgumentException("Prefix " + prefix
+ " required in format <nethandle>:<interface>");
}
+ final long netHandle = Long.parseLong(prefixParts[0]);
+ final Network network = Network.fromNetworkHandle(netHandle);
final WakeupEvent event = new WakeupEvent();
event.iface = prefixParts[1];
event.uid = uid;
event.ethertype = ethertype;
- event.dstHwAddr = MacAddress.fromBytes(dstHw);
+ if (ArrayUtils.isEmpty(dstHw)) {
+ if (hasWifiTransport(network)) {
+ Log.e(TAG, "Empty mac address on WiFi transport, network: " + network);
+ }
+ event.dstHwAddr = null;
+ } else {
+ event.dstHwAddr = MacAddress.fromBytes(dstHw);
+ }
event.srcIp = srcIp;
event.dstIp = dstIp;
event.ipNextHeader = ipNextHeader;
@@ -306,14 +321,12 @@ public class NetdEventListenerService extends BaseNetdEventListener {
final BatteryStatsInternal bsi = LocalServices.getService(BatteryStatsInternal.class);
if (bsi != null) {
- final long netHandle = Long.parseLong(prefixParts[0]);
final long elapsedMs = SystemClock.elapsedRealtime() + event.timestampMs
- System.currentTimeMillis();
- bsi.noteCpuWakingNetworkPacket(Network.fromNetworkHandle(netHandle), elapsedMs,
- event.uid);
+ bsi.noteCpuWakingNetworkPacket(network, elapsedMs, event.uid);
}
- final String dstMac = event.dstHwAddr.toString();
+ final String dstMac = String.valueOf(event.dstHwAddr);
FrameworkStatsLog.write(FrameworkStatsLog.PACKET_WAKEUP_OCCURRED,
uid, event.iface, ethertype, dstMac, srcIp, dstIp, ipNextHeader, srcPort, dstPort);
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 1dc2725feb1b..c678a92af13a 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -85,6 +85,7 @@ import android.net.NetworkScore;
import android.net.NetworkSpecifier;
import android.net.RouteInfo;
import android.net.TelephonyNetworkSpecifier;
+import android.net.TransportInfo;
import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
@@ -107,6 +108,8 @@ import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.net.ipsec.ike.exceptions.IkeTimeoutException;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnTransportInfo;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -453,22 +456,22 @@ public class Vpn {
private static class CarrierConfigInfo {
public final String mccMnc;
- public final int keepaliveDelayMs;
+ public final int keepaliveDelaySec;
public final int encapType;
public final int ipVersion;
- CarrierConfigInfo(String mccMnc, int keepaliveDelayMs,
+ CarrierConfigInfo(String mccMnc, int keepaliveDelaySec,
int encapType,
int ipVersion) {
this.mccMnc = mccMnc;
- this.keepaliveDelayMs = keepaliveDelayMs;
+ this.keepaliveDelaySec = keepaliveDelaySec;
this.encapType = encapType;
this.ipVersion = ipVersion;
}
@Override
public String toString() {
- return "CarrierConfigInfo(" + mccMnc + ") [keepaliveDelayMs=" + keepaliveDelayMs
+ return "CarrierConfigInfo(" + mccMnc + ") [keepaliveDelaySec=" + keepaliveDelaySec
+ ", encapType=" + encapType + ", ipVersion=" + ipVersion + "]";
}
}
@@ -3556,39 +3559,63 @@ public class Vpn {
}
private int guessEspIpVersionForNetwork() {
- final CarrierConfigInfo carrierconfig = getCarrierConfig();
+ if (mUnderlyingNetworkCapabilities.getTransportInfo() instanceof VcnTransportInfo) {
+ Log.d(TAG, "Running over VCN, esp IP version is auto");
+ return ESP_IP_VERSION_AUTO;
+ }
+ final CarrierConfigInfo carrierconfig = getCarrierConfigForUnderlyingNetwork();
final int ipVersion = (carrierconfig != null)
? carrierconfig.ipVersion : ESP_IP_VERSION_AUTO;
if (carrierconfig != null) {
- Log.d(TAG, "Get customized IP version(" + ipVersion + ") on SIM("
+ Log.d(TAG, "Get customized IP version (" + ipVersion + ") on SIM (mccmnc="
+ carrierconfig.mccMnc + ")");
}
return ipVersion;
}
private int guessEspEncapTypeForNetwork() {
- final CarrierConfigInfo carrierconfig = getCarrierConfig();
+ if (mUnderlyingNetworkCapabilities.getTransportInfo() instanceof VcnTransportInfo) {
+ Log.d(TAG, "Running over VCN, encap type is auto");
+ return ESP_ENCAP_TYPE_AUTO;
+ }
+ final CarrierConfigInfo carrierconfig = getCarrierConfigForUnderlyingNetwork();
final int encapType = (carrierconfig != null)
? carrierconfig.encapType : ESP_ENCAP_TYPE_AUTO;
if (carrierconfig != null) {
- Log.d(TAG, "Get customized encap type(" + encapType + ") on SIM("
+ Log.d(TAG, "Get customized encap type (" + encapType + ") on SIM (mccmnc="
+ carrierconfig.mccMnc + ")");
}
return encapType;
}
+
private int guessNattKeepaliveTimerForNetwork() {
- final CarrierConfigInfo carrierconfig = getCarrierConfig();
- final int natKeepalive = (carrierconfig != null)
- ? carrierconfig.keepaliveDelayMs : AUTOMATIC_KEEPALIVE_DELAY_SECONDS;
+ final TransportInfo transportInfo = mUnderlyingNetworkCapabilities.getTransportInfo();
+ if (transportInfo instanceof VcnTransportInfo) {
+ final int nattKeepaliveSec =
+ ((VcnTransportInfo) transportInfo).getMinUdpPort4500NatTimeoutSeconds();
+ Log.d(TAG, "Running over VCN, keepalive timer : " + nattKeepaliveSec + "s");
+ if (VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
+ != nattKeepaliveSec) {
+ return nattKeepaliveSec;
+ }
+ // else fall back to carrier config, if any
+ }
+ final CarrierConfigInfo carrierconfig = getCarrierConfigForUnderlyingNetwork();
+ final int nattKeepaliveSec = (carrierconfig != null)
+ ? carrierconfig.keepaliveDelaySec : AUTOMATIC_KEEPALIVE_DELAY_SECONDS;
if (carrierconfig != null) {
- Log.d(TAG, "Get customized keepalive(" + natKeepalive + ") on SIM("
+ Log.d(TAG, "Get customized keepalive (" + nattKeepaliveSec + "s) on SIM (mccmnc="
+ carrierconfig.mccMnc + ")");
}
- return natKeepalive;
+ return nattKeepaliveSec;
}
- private CarrierConfigInfo getCarrierConfig() {
+ /**
+ * Returns the carrier config for the underlying network, or null if not a cell network.
+ */
+ @Nullable
+ private CarrierConfigInfo getCarrierConfigForUnderlyingNetwork() {
final int subId = getCellSubIdForNetworkCapabilities(mUnderlyingNetworkCapabilities);
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
Log.d(TAG, "Underlying network is not a cellular network");
diff --git a/services/core/java/com/android/server/display/color/CctEvaluator.java b/services/core/java/com/android/server/display/color/CctEvaluator.java
new file mode 100644
index 000000000000..878f7e5116b8
--- /dev/null
+++ b/services/core/java/com/android/server/display/color/CctEvaluator.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.color;
+
+import android.animation.TypeEvaluator;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+
+/**
+ * Interpolates between CCT values by a given step.
+ */
+class CctEvaluator implements TypeEvaluator<Integer> {
+
+ private static final String TAG = "CctEvaluator";
+
+ /**
+ * The minimum input value, which will represent index 0 in the mValues array. Each
+ * subsequent input value is offset by this amount.
+ */
+ private final int mIndexOffset;
+ /**
+ * Cached step values at each CCT value (offset by the {@link #mIndexOffset} above). For
+ * example, if the minimum CCT is 2000K (which is set to mIndexOffset), then the 0th index of
+ * this array is equivalent to the step value at 2000K, 1st index corresponds to 2001K, and so
+ * on.
+ */
+ @VisibleForTesting
+ final int[] mStepsAtOffsetCcts;
+ /**
+ * Pre-computed stepped CCTs. These will be accessed frequently; the memory cost of caching them
+ * is well-spent.
+ */
+ @VisibleForTesting
+ final int[] mSteppedCctsAtOffsetCcts;
+
+ CctEvaluator(int min, int max, int[] cctRangeMinimums, int[] steps) {
+ final int delta = max - min + 1;
+ mStepsAtOffsetCcts = new int[delta];
+ mSteppedCctsAtOffsetCcts = new int[delta];
+ mIndexOffset = min;
+
+ final int parallelArraysLength = cctRangeMinimums.length;
+ if (cctRangeMinimums.length != steps.length) {
+ Slog.e(TAG,
+ "Parallel arrays cctRangeMinimums and steps are different lengths; setting "
+ + "step of 1");
+ setStepOfOne();
+ } else if (parallelArraysLength == 0) {
+ Slog.e(TAG, "No cctRangeMinimums or steps are set; setting step of 1");
+ setStepOfOne();
+ } else {
+ int parallelArraysIndex = 0;
+ int index = 0;
+ int lastSteppedCct = Integer.MIN_VALUE;
+ while (index < delta) {
+ final int cct = index + mIndexOffset;
+ int nextParallelArraysIndex = parallelArraysIndex + 1;
+ while (nextParallelArraysIndex < parallelArraysLength
+ && cct >= cctRangeMinimums[nextParallelArraysIndex]) {
+ parallelArraysIndex = nextParallelArraysIndex;
+ nextParallelArraysIndex++;
+ }
+ mStepsAtOffsetCcts[index] = steps[parallelArraysIndex];
+ if (lastSteppedCct == Integer.MIN_VALUE
+ || Math.abs(lastSteppedCct - cct) >= steps[parallelArraysIndex]) {
+ lastSteppedCct = cct;
+ }
+ mSteppedCctsAtOffsetCcts[index] = lastSteppedCct;
+ index++;
+ }
+ }
+ }
+
+ @Override
+ public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
+ final int cct = (int) (startValue + fraction * (endValue - startValue));
+ final int index = cct - mIndexOffset;
+ if (index < 0 || index >= mSteppedCctsAtOffsetCcts.length) {
+ Slog.e(TAG, "steppedCctValueAt: returning same since invalid requested index=" + index);
+ return cct;
+ }
+ return mSteppedCctsAtOffsetCcts[index];
+ }
+
+ private void setStepOfOne() {
+ Arrays.fill(mStepsAtOffsetCcts, 1);
+ for (int i = 0; i < mSteppedCctsAtOffsetCcts.length; i++) {
+ mSteppedCctsAtOffsetCcts[i] = mIndexOffset + i;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 0284d9c68689..c0ea5fead9a5 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -180,6 +180,8 @@ public final class ColorDisplayService extends SystemService {
*/
private SparseIntArray mColorModeCompositionColorSpaces = null;
+ private final Object mCctTintApplierLock = new Object();
+
public ColorDisplayService(Context context) {
super(context);
mHandler = new TintHandler(DisplayThread.get().getLooper());
@@ -698,6 +700,79 @@ public final class ColorDisplayService extends SystemService {
}
}
+ private void applyTintByCct(ColorTemperatureTintController tintController, boolean immediate) {
+ synchronized (mCctTintApplierLock) {
+ tintController.cancelAnimator();
+
+ final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+ final int from = tintController.getAppliedCct();
+ final int to = tintController.isActivated() ? tintController.getTargetCct()
+ : tintController.getDisabledCct();
+
+ if (immediate) {
+ Slog.d(TAG, tintController.getClass().getSimpleName()
+ + " applied immediately: toCct=" + to + " fromCct=" + from);
+ dtm.setColorMatrix(tintController.getLevel(),
+ tintController.computeMatrixForCct(to));
+ tintController.setAppliedCct(to);
+ } else {
+ Slog.d(TAG, tintController.getClass().getSimpleName() + " animation started: toCct="
+ + to + " fromCct=" + from);
+ ValueAnimator valueAnimator = ValueAnimator.ofInt(from, to);
+ tintController.setAnimator(valueAnimator);
+ final CctEvaluator evaluator = tintController.getEvaluator();
+ if (evaluator != null) {
+ valueAnimator.setEvaluator(evaluator);
+ }
+ valueAnimator.setDuration(tintController.getTransitionDurationMilliseconds());
+ valueAnimator.setInterpolator(AnimationUtils.loadInterpolator(
+ getContext(), android.R.interpolator.linear));
+ valueAnimator.addUpdateListener((ValueAnimator animator) -> {
+ synchronized (mCctTintApplierLock) {
+ final int value = (int) animator.getAnimatedValue();
+ if (value != tintController.getAppliedCct()) {
+ dtm.setColorMatrix(tintController.getLevel(),
+ tintController.computeMatrixForCct(value));
+ tintController.setAppliedCct(value);
+ }
+ }
+ });
+ valueAnimator.addListener(new AnimatorListenerAdapter() {
+
+ private boolean mIsCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ Slog.d(TAG, tintController.getClass().getSimpleName()
+ + " animation cancelled");
+ mIsCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ synchronized (mCctTintApplierLock) {
+ Slog.d(TAG, tintController.getClass().getSimpleName()
+ + " animation ended: wasCancelled=" + mIsCancelled
+ + " toCct=" + to
+ + " fromCct=" + from);
+ if (!mIsCancelled) {
+ // Ensure final color matrix is set at the end of the animation.
+ // If the animation is cancelled then don't set the final color
+ // matrix so the new animator can pick up from where this one left
+ // off.
+ dtm.setColorMatrix(tintController.getLevel(),
+ tintController.computeMatrixForCct(to));
+ tintController.setAppliedCct(to);
+ }
+ tintController.setAnimator(null);
+ }
+ }
+ });
+ valueAnimator.start();
+ }
+ }
+ }
+
/**
* Returns the first date time corresponding to the local time that occurs before the provided
* date time.
@@ -747,7 +822,7 @@ public final class ColorDisplayService extends SystemService {
// If disabled, clear the tint. If enabled, do nothing more here and let the next
// temperature update set the correct tint.
- if (!activated) {
+ if (oldActivated && !activated) {
mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
}
}
@@ -1452,7 +1527,7 @@ public final class ColorDisplayService extends SystemService {
public class ColorDisplayServiceInternal {
/** Sets whether DWB should be allowed in the current state. */
- public void setDisplayWhiteBalanceAllowed(boolean allowed) {
+ public void setDisplayWhiteBalanceAllowed(boolean allowed) {
mDisplayWhiteBalanceTintController.setAllowed(allowed);
updateDisplayWhiteBalanceStatus();
}
@@ -1464,8 +1539,8 @@ public final class ColorDisplayService extends SystemService {
* @param cct the color temperature in Kelvin.
*/
public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
- // Update the transform matrix even if it can't be applied.
- mDisplayWhiteBalanceTintController.setMatrix(cct);
+ // Update the transform target CCT even if it can't be applied.
+ mDisplayWhiteBalanceTintController.setTargetCct(cct);
if (mDisplayWhiteBalanceTintController.isActivated()) {
mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
@@ -1601,7 +1676,7 @@ public final class ColorDisplayService extends SystemService {
applyTint(mNightDisplayTintController, false);
break;
case MSG_APPLY_DISPLAY_WHITE_BALANCE:
- applyTint(mDisplayWhiteBalanceTintController, false);
+ applyTintByCct(mDisplayWhiteBalanceTintController, false);
break;
}
}
diff --git a/services/core/java/com/android/server/display/color/ColorTemperatureTintController.java b/services/core/java/com/android/server/display/color/ColorTemperatureTintController.java
new file mode 100644
index 000000000000..0fbd9d409986
--- /dev/null
+++ b/services/core/java/com/android/server/display/color/ColorTemperatureTintController.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.color;
+
+abstract class ColorTemperatureTintController extends TintController {
+
+ abstract int getAppliedCct();
+
+ abstract void setAppliedCct(int cct);
+
+ abstract int getTargetCct();
+
+ abstract void setTargetCct(int cct);
+
+ /**
+ * Returns the CCT value most closely associated with the "disabled" (identity) matrix for
+ * this device, to use as the target when deactivating this transform.
+ */
+ abstract int getDisabledCct();
+
+ abstract float[] computeMatrixForCct(int cct);
+
+ abstract CctEvaluator getEvaluator();
+}
diff --git a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
index 106ac0c0d478..bf0139f347f8 100644
--- a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
+++ b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
@@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.Size;
import android.content.Context;
import android.content.res.Resources;
@@ -36,7 +37,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
-final class DisplayWhiteBalanceTintController extends TintController {
+final class DisplayWhiteBalanceTintController extends ColorTemperatureTintController {
// Three chromaticity coordinates per color: X, Y, and Z
private static final int NUM_VALUES_PER_PRIMARY = 3;
@@ -52,9 +53,11 @@ final class DisplayWhiteBalanceTintController extends TintController {
private int mTemperatureDefault;
@VisibleForTesting
float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ private int mDisplayNominalWhiteCct;
@VisibleForTesting
ColorSpace.Rgb mDisplayColorSpaceRGB;
private float[] mChromaticAdaptationMatrix;
+ // The temperature currently represented in the matrix.
@VisibleForTesting
int mCurrentColorTemperature;
private float[] mCurrentColorTemperatureXYZ;
@@ -65,6 +68,9 @@ final class DisplayWhiteBalanceTintController extends TintController {
private Boolean mIsAvailable;
// This feature becomes disallowed if the device is in an unsupported strong/light state.
private boolean mIsAllowed = true;
+ private int mTargetCct;
+ private int mAppliedCct;
+ private CctEvaluator mCctEvaluator;
private final DisplayManagerInternal mDisplayManagerInternal;
@@ -108,6 +114,9 @@ final class DisplayWhiteBalanceTintController extends TintController {
displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
}
+ final int displayNominalWhiteCct = res.getInteger(
+ R.integer.config_displayWhiteBalanceDisplayNominalWhiteCct);
+
final int colorTemperatureMin = res.getInteger(
R.integer.config_displayWhiteBalanceColorTemperatureMin);
if (colorTemperatureMin <= 0) {
@@ -124,19 +133,28 @@ final class DisplayWhiteBalanceTintController extends TintController {
return;
}
- final int colorTemperature = res.getInteger(
+ final int defaultTemperature = res.getInteger(
R.integer.config_displayWhiteBalanceColorTemperatureDefault);
mTransitionDuration = res.getInteger(
R.integer.config_displayWhiteBalanceTransitionTime);
+ int[] cctRangeMinimums = res.getIntArray(
+ R.array.config_displayWhiteBalanceDisplayRangeMinimums);
+ int[] steps = res.getIntArray(R.array.config_displayWhiteBalanceDisplaySteps);
+
synchronized (mLock) {
mDisplayColorSpaceRGB = displayColorSpaceRGB;
mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
+ mDisplayNominalWhiteCct = displayNominalWhiteCct;
+ mTargetCct = mDisplayNominalWhiteCct;
+ mAppliedCct = mDisplayNominalWhiteCct;
mTemperatureMin = colorTemperatureMin;
mTemperatureMax = colorTemperatureMax;
- mTemperatureDefault = colorTemperature;
+ mTemperatureDefault = defaultTemperature;
mSetUp = true;
+ mCctEvaluator = new CctEvaluator(mTemperatureMin, mTemperatureMax,
+ cctRangeMinimums, steps);
}
setMatrix(mTemperatureDefault);
@@ -144,8 +162,16 @@ final class DisplayWhiteBalanceTintController extends TintController {
@Override
public float[] getMatrix() {
- return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance
- : ColorDisplayService.MATRIX_IDENTITY;
+ if (!mSetUp || !isActivated()) {
+ return ColorDisplayService.MATRIX_IDENTITY;
+ }
+ computeMatrixForCct(mAppliedCct);
+ return mMatrixDisplayWhiteBalance;
+ }
+
+ @Override
+ public int getTargetCct() {
+ return mTargetCct;
}
/**
@@ -174,6 +200,12 @@ final class DisplayWhiteBalanceTintController extends TintController {
@Override
public void setMatrix(int cct) {
+ setTargetCct(cct);
+ computeMatrixForCct(mTargetCct);
+ }
+
+ @Override
+ public void setTargetCct(int cct) {
if (!mSetUp) {
Slog.w(ColorDisplayService.TAG,
"Can't set display white balance temperature: uninitialized");
@@ -183,50 +215,93 @@ final class DisplayWhiteBalanceTintController extends TintController {
if (cct < mTemperatureMin) {
Slog.w(ColorDisplayService.TAG,
"Requested display color temperature is below allowed minimum");
- cct = mTemperatureMin;
+ mTargetCct = mTemperatureMin;
} else if (cct > mTemperatureMax) {
Slog.w(ColorDisplayService.TAG,
"Requested display color temperature is above allowed maximum");
- cct = mTemperatureMax;
+ mTargetCct = mTemperatureMax;
+ } else {
+ mTargetCct = cct;
+ }
+ }
+
+ @Override
+ public int getDisabledCct() {
+ return mDisplayNominalWhiteCct;
+ }
+
+ @Override
+ public float[] computeMatrixForCct(int cct) {
+ if (!mSetUp || cct == 0) {
+ Slog.w(ColorDisplayService.TAG, "Couldn't compute matrix for cct=" + cct);
+ return ColorDisplayService.MATRIX_IDENTITY;
}
synchronized (mLock) {
mCurrentColorTemperature = cct;
- // Adapt the display's nominal white point to match the requested CCT value
- mCurrentColorTemperatureXYZ = ColorSpace.cctToXyz(cct);
-
- mChromaticAdaptationMatrix =
- ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
- mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
-
- // Convert the adaptation matrix to RGB space
- float[] result = mul3x3(mChromaticAdaptationMatrix,
- mDisplayColorSpaceRGB.getTransform());
- result = mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
-
- // Normalize the transform matrix to peak white value in RGB space
- final float adaptedMaxR = result[0] + result[3] + result[6];
- final float adaptedMaxG = result[1] + result[4] + result[7];
- final float adaptedMaxB = result[2] + result[5] + result[8];
- final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
-
- Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
- for (int i = 0; i < result.length; i++) {
- result[i] /= denum;
- if (!isColorMatrixCoeffValid(result[i])) {
- Slog.e(ColorDisplayService.TAG, "Invalid DWB color matrix");
- return;
- }
+ if (cct == mDisplayNominalWhiteCct && !isActivated()) {
+ // DWB is finished turning off. Clear the matrix.
+ Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+ } else {
+ computeMatrixForCctLocked(cct);
}
- java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
- java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
- java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+ Slog.d(ColorDisplayService.TAG, "computeDisplayWhiteBalanceMatrix: cct =" + cct
+ + " matrix =" + matrixToString(mMatrixDisplayWhiteBalance, 16));
+
+ return mMatrixDisplayWhiteBalance;
}
+ }
+
+ private void computeMatrixForCctLocked(int cct) {
+ // Adapt the display's nominal white point to match the requested CCT value
+ mCurrentColorTemperatureXYZ = ColorSpace.cctToXyz(cct);
+
+ mChromaticAdaptationMatrix =
+ ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+ mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
- Slog.d(ColorDisplayService.TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct
- + " matrix = " + matrixToString(mMatrixDisplayWhiteBalance, 16));
+ // Convert the adaptation matrix to RGB space
+ float[] result = mul3x3(mChromaticAdaptationMatrix,
+ mDisplayColorSpaceRGB.getTransform());
+ result = mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
+
+ // Normalize the transform matrix to peak white value in RGB space
+ final float adaptedMaxR = result[0] + result[3] + result[6];
+ final float adaptedMaxG = result[1] + result[4] + result[7];
+ final float adaptedMaxB = result[2] + result[5] + result[8];
+ final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+
+ Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+
+ for (int i = 0; i < result.length; i++) {
+ result[i] /= denum;
+ if (!isColorMatrixCoeffValid(result[i])) {
+ Slog.e(ColorDisplayService.TAG, "Invalid DWB color matrix");
+ return;
+ }
+ }
+
+ java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
+ java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
+ java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+ }
+
+ @Override
+ int getAppliedCct() {
+ return mAppliedCct;
+ }
+
+ @Override
+ void setAppliedCct(int cct) {
+ mAppliedCct = cct;
+ }
+
+ @Override
+ @Nullable
+ CctEvaluator getEvaluator() {
+ return mCctEvaluator;
}
@Override
@@ -258,7 +333,10 @@ final class DisplayWhiteBalanceTintController extends TintController {
pw.println(" mTemperatureMin = " + mTemperatureMin);
pw.println(" mTemperatureMax = " + mTemperatureMax);
pw.println(" mTemperatureDefault = " + mTemperatureDefault);
+ pw.println(" mDisplayNominalWhiteCct = " + mDisplayNominalWhiteCct);
pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature);
+ pw.println(" mTargetCct = " + mTargetCct);
+ pw.println(" mAppliedCct = " + mAppliedCct);
pw.println(" mCurrentColorTemperatureXYZ = "
+ matrixToString(mCurrentColorTemperatureXYZ, 3));
pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = "
@@ -340,11 +418,7 @@ final class DisplayWhiteBalanceTintController extends TintController {
}
private boolean isColorMatrixCoeffValid(float coeff) {
- if (Float.isNaN(coeff) || Float.isInfinite(coeff)) {
- return false;
- }
-
- return true;
+ return !Float.isNaN(coeff) && !Float.isInfinite(coeff);
}
private boolean isColorMatrixValid(float[] matrix) {
@@ -352,8 +426,8 @@ final class DisplayWhiteBalanceTintController extends TintController {
return false;
}
- for (int i = 0; i < matrix.length; i++) {
- if (!isColorMatrixCoeffValid(matrix[i])) {
+ for (float value : matrix) {
+ if (!isColorMatrixCoeffValid(value)) {
return false;
}
}
diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java
index c53ac06c66e1..384333a574b5 100644
--- a/services/core/java/com/android/server/display/color/TintController.java
+++ b/services/core/java/com/android/server/display/color/TintController.java
@@ -16,6 +16,7 @@
package com.android.server.display.color;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.util.Slog;
@@ -28,14 +29,14 @@ abstract class TintController {
*/
private static final long TRANSITION_DURATION = 3000L;
- private ColorDisplayService.TintValueAnimator mAnimator;
+ private ValueAnimator mAnimator;
private Boolean mIsActivated;
- public ColorDisplayService.TintValueAnimator getAnimator() {
+ public ValueAnimator getAnimator() {
return mAnimator;
}
- public void setAnimator(ColorDisplayService.TintValueAnimator animator) {
+ public void setAnimator(ValueAnimator animator) {
mAnimator = animator;
}
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index d8716b328230..6ec4022fe15a 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -562,7 +562,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
key.append(",languageTag:").append(inputDevice.getKeyboardLanguageTag());
}
if (!TextUtils.isEmpty(inputDevice.getKeyboardLayoutType())) {
- key.append(",layoutType:").append(inputDevice.getKeyboardLanguageTag());
+ key.append(",layoutType:").append(inputDevice.getKeyboardLayoutType());
}
}
return key.toString();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c70d55510493..57f8d1478905 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -856,13 +856,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@GuardedBy("ImfLock.class")
private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
- private static final class SoftInputShowHideHistory {
+ @VisibleForTesting
+ static final class SoftInputShowHideHistory {
private final Entry[] mEntries = new Entry[16];
private int mNextIndex = 0;
private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
- private static final class Entry {
+ static final class Entry {
final int mSequenceNumber = sSequenceNumber.getAndIncrement();
+ @Nullable
final ClientState mClientState;
@SoftInputModeFlags
final int mFocusedWindowSoftInputMode;
@@ -874,7 +876,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final boolean mInFullscreenMode;
@NonNull
final String mFocusedWindowName;
- @NonNull
+ @Nullable
final EditorInfo mEditorInfo;
@NonNull
final String mRequestWindowName;
@@ -953,9 +955,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
pw.print(prefix);
pw.print(" editorInfo: ");
- pw.print(" inputType=" + entry.mEditorInfo.inputType);
- pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions);
- pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId);
+ if (entry.mEditorInfo != null) {
+ pw.print(" inputType=" + entry.mEditorInfo.inputType);
+ pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions);
+ pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId);
+ } else {
+ pw.println("null");
+ }
pw.print(prefix);
pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString(
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 33e6a8f15df2..f0ab815db2c1 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -316,7 +316,6 @@ import com.android.server.notification.toast.TextToastRecord;
import com.android.server.notification.toast.ToastRecord;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.powerstats.StatsPullAtomCallbackImpl;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -2559,8 +2558,8 @@ public class NotificationManagerService extends SystemService {
Context.STATS_MANAGER),
getContext().getSystemService(TelephonyManager.class),
LocalServices.getService(ActivityManagerInternal.class),
- createToastRateLimiter(), new PermissionHelper(LocalServices.getService(
- PermissionManagerServiceInternal.class), AppGlobals.getPackageManager(),
+ createToastRateLimiter(), new PermissionHelper(getContext(),
+ AppGlobals.getPackageManager(),
AppGlobals.getPermissionManager()),
LocalServices.getService(UsageStatsManagerInternal.class),
getContext().getSystemService(TelecomManager.class),
@@ -11599,6 +11598,8 @@ public class NotificationManagerService extends SystemService {
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
listener.onNotificationPosted(sbnHolder, rankingUpdate);
+ } catch (android.os.DeadObjectException ex) {
+ Slog.wtf(TAG, "unable to notify listener (posted): " + info, ex);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener (posted): " + info, ex);
}
@@ -11620,6 +11621,8 @@ public class NotificationManagerService extends SystemService {
reason = REASON_LISTENER_CANCEL;
}
listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
+ } catch (android.os.DeadObjectException ex) {
+ Slog.wtf(TAG, "unable to notify listener (removed): " + info, ex);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener (removed): " + info, ex);
}
@@ -11630,6 +11633,8 @@ public class NotificationManagerService extends SystemService {
final INotificationListener listener = (INotificationListener) info.service;
try {
listener.onNotificationRankingUpdate(rankingUpdate);
+ } catch (android.os.DeadObjectException ex) {
+ Slog.wtf(TAG, "unable to notify listener (ranking update): " + info, ex);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener (ranking update): " + info, ex);
}
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index b6fd822b7687..93c83e181ec1 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -25,6 +25,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
+import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -37,7 +38,6 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.util.Collections;
import java.util.HashSet;
@@ -53,13 +53,13 @@ public final class PermissionHelper {
private static final String NOTIFICATION_PERMISSION = Manifest.permission.POST_NOTIFICATIONS;
- private final PermissionManagerServiceInternal mPmi;
+ private final Context mContext;
private final IPackageManager mPackageManager;
private final IPermissionManager mPermManager;
- public PermissionHelper(PermissionManagerServiceInternal pmi, IPackageManager packageManager,
+ public PermissionHelper(Context context, IPackageManager packageManager,
IPermissionManager permManager) {
- mPmi = pmi;
+ mContext = context;
mPackageManager = packageManager;
mPermManager = permManager;
}
@@ -71,7 +71,7 @@ public final class PermissionHelper {
public boolean hasPermission(int uid) {
final long callingId = Binder.clearCallingIdentity();
try {
- return mPmi.checkUidPermission(uid, NOTIFICATION_PERMISSION) == PERMISSION_GRANTED;
+ return mContext.checkPermission(NOTIFICATION_PERMISSION, -1, uid) == PERMISSION_GRANTED;
} finally {
Binder.restoreCallingIdentity(callingId);
}
@@ -193,8 +193,8 @@ public final class PermissionHelper {
return;
}
- boolean currentlyGranted = mPmi.checkPermission(packageName, NOTIFICATION_PERMISSION,
- userId) != PackageManager.PERMISSION_DENIED;
+ int uid = mPackageManager.getPackageUid(packageName, 0, userId);
+ boolean currentlyGranted = hasPermission(uid);
if (grant && !currentlyGranted) {
mPermManager.grantRuntimePermission(packageName, NOTIFICATION_PERMISSION, userId);
} else if (!grant && currentlyGranted) {
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index a267e8afa78d..5932929a69c4 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -4360,12 +4360,22 @@ final class InstallPackageHelper {
// A new application appeared on /system, and we are seeing it for the first time.
// Its also not updated as we don't have a copy of it on /data. So, scan it in a
- // STOPPED state. Ignore if it's an APEX package since stopped state does not affect them.
+ // STOPPED state.
+ // We'll skip this step under the following conditions:
+ // - It's "android"
+ // - It's an APEX or overlay package since stopped state does not affect them.
+ // - It is enumerated with a <initial-package-state> tag having the stopped attribute
+ // set to false
final boolean isApexPkg = (scanFlags & SCAN_AS_APEX) != 0;
- if (mPm.mShouldStopSystemPackagesByDefault && scanSystemPartition
- && !pkgAlreadyExists && !isApexPkg) {
+ if (mPm.mShouldStopSystemPackagesByDefault
+ && scanSystemPartition
+ && !pkgAlreadyExists
+ && !isApexPkg
+ && !parsedPackage.isOverlayIsStatic()
+ ) {
String packageName = parsedPackage.getPackageName();
- if (!mPm.mInitialNonStoppedSystemPackages.contains(packageName)) {
+ if (!mPm.mInitialNonStoppedSystemPackages.contains(packageName)
+ && !"android".contentEquals(packageName)) {
scanFlags |= SCAN_AS_STOPPED_SYSTEM_APP;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 29c5adaea844..97e7f6f41703 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1148,12 +1148,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
info.userId = userId;
info.installerPackageName = mInstallSource.mInstallerPackageName;
info.installerAttributionTag = mInstallSource.mInstallerAttributionTag;
+ info.resolvedBaseCodePath = null;
if (mContext.checkCallingOrSelfPermission(
Manifest.permission.READ_INSTALLED_SESSION_PATHS)
- == PackageManager.PERMISSION_GRANTED && mResolvedBaseFile != null) {
- info.resolvedBaseCodePath = mResolvedBaseFile.getAbsolutePath();
- } else {
- info.resolvedBaseCodePath = null;
+ == PackageManager.PERMISSION_GRANTED) {
+ File file = mResolvedBaseFile;
+ if (file == null) {
+ // Try to guess mResolvedBaseFile file.
+ final List<File> addedFiles = getAddedApksLocked();
+ if (addedFiles.size() > 0) {
+ file = addedFiles.get(0);
+ }
+ }
+ if (file != null) {
+ info.resolvedBaseCodePath = file.getAbsolutePath();
+ }
}
info.progress = progress;
info.sealed = mSealed;
@@ -1355,9 +1364,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private String[] getStageDirContentsLocked() {
+ if (stageDir == null) {
+ return EmptyArray.STRING;
+ }
String[] result = stageDir.list();
if (result == null) {
- result = EmptyArray.STRING;
+ return EmptyArray.STRING;
}
return result;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 84a9888d2458..2f0cea363d17 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -93,7 +93,6 @@ import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.text.format.TimeMigrationUtils;
import android.util.ArraySet;
-import android.util.AtomicFile;
import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Slog;
@@ -149,6 +148,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
@@ -321,8 +321,7 @@ public class ShortcutService extends IShortcutService.Stub {
private final ArrayList<LauncherApps.ShortcutChangeCallback> mShortcutChangeCallbacks =
new ArrayList<>(1);
- @GuardedBy("mLock")
- private long mRawLastResetTime;
+ private final AtomicLong mRawLastResetTime = new AtomicLong(0);
/**
* User ID -> UserShortcuts
@@ -756,10 +755,15 @@ public class ShortcutService extends IShortcutService.Stub {
}
/** Return the base state file name */
- private AtomicFile getBaseStateFile() {
- final File path = new File(injectSystemDataPath(), FILENAME_BASE_STATE);
- path.mkdirs();
- return new AtomicFile(path);
+ final ResilientAtomicFile getBaseStateFile() {
+ File mainFile = new File(injectSystemDataPath(), FILENAME_BASE_STATE);
+ File temporaryBackup = new File(injectSystemDataPath(),
+ FILENAME_BASE_STATE + ".backup");
+ File reserveCopy = new File(injectSystemDataPath(),
+ FILENAME_BASE_STATE + ".reservecopy");
+ int fileMode = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH;
+ return new ResilientAtomicFile(mainFile, temporaryBackup, reserveCopy, fileMode,
+ "base shortcut", null);
}
/**
@@ -976,80 +980,91 @@ public class ShortcutService extends IShortcutService.Stub {
writeAttr(out, name, intent.toUri(/* flags =*/ 0));
}
- @GuardedBy("mLock")
@VisibleForTesting
- void saveBaseStateLocked() {
- final AtomicFile file = getBaseStateFile();
- if (DEBUG || DEBUG_REBOOT) {
- Slog.d(TAG, "Saving to " + file.getBaseFile());
- }
+ void saveBaseState() {
+ try (ResilientAtomicFile file = getBaseStateFile()) {
+ if (DEBUG || DEBUG_REBOOT) {
+ Slog.d(TAG, "Saving to " + file.getBaseFile());
+ }
- FileOutputStream outs = null;
- try {
- outs = file.startWrite();
+ FileOutputStream outs = null;
+ try {
+ synchronized (mLock) {
+ outs = file.startWrite();
+ }
- // Write to XML
- TypedXmlSerializer out = Xml.resolveSerializer(outs);
- out.startDocument(null, true);
- out.startTag(null, TAG_ROOT);
+ // Write to XML
+ TypedXmlSerializer out = Xml.resolveSerializer(outs);
+ out.startDocument(null, true);
+ out.startTag(null, TAG_ROOT);
- // Body.
- writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime);
+ // Body.
+ // No locking required. Ok to add lock later if we save more data.
+ writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime.get());
- // Epilogue.
- out.endTag(null, TAG_ROOT);
- out.endDocument();
+ // Epilogue.
+ out.endTag(null, TAG_ROOT);
+ out.endDocument();
- // Close.
- file.finishWrite(outs);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
- file.failWrite(outs);
+ // Close.
+ file.finishWrite(outs);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
+ file.failWrite(outs);
+ }
}
}
@GuardedBy("mLock")
private void loadBaseStateLocked() {
- mRawLastResetTime = 0;
-
- final AtomicFile file = getBaseStateFile();
- if (DEBUG || DEBUG_REBOOT) {
- Slog.d(TAG, "Loading from " + file.getBaseFile());
- }
- try (FileInputStream in = file.openRead()) {
- TypedXmlPullParser parser = Xml.resolvePullParser(in);
+ mRawLastResetTime.set(0);
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (type != XmlPullParser.START_TAG) {
- continue;
+ try (ResilientAtomicFile file = getBaseStateFile()) {
+ if (DEBUG || DEBUG_REBOOT) {
+ Slog.d(TAG, "Loading from " + file.getBaseFile());
+ }
+ FileInputStream in = null;
+ try {
+ in = file.openRead();
+ if (in == null) {
+ throw new FileNotFoundException(file.getBaseFile().getAbsolutePath());
}
- final int depth = parser.getDepth();
- // Check the root tag
- final String tag = parser.getName();
- if (depth == 1) {
- if (!TAG_ROOT.equals(tag)) {
- Slog.e(TAG, "Invalid root tag: " + tag);
- return;
+
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final int depth = parser.getDepth();
+ // Check the root tag
+ final String tag = parser.getName();
+ if (depth == 1) {
+ if (!TAG_ROOT.equals(tag)) {
+ Slog.e(TAG, "Invalid root tag: " + tag);
+ return;
+ }
+ continue;
+ }
+ // Assume depth == 2
+ switch (tag) {
+ case TAG_LAST_RESET_TIME:
+ mRawLastResetTime.set(parseLongAttribute(parser, ATTR_VALUE));
+ break;
+ default:
+ Slog.e(TAG, "Invalid tag: " + tag);
+ break;
}
- continue;
- }
- // Assume depth == 2
- switch (tag) {
- case TAG_LAST_RESET_TIME:
- mRawLastResetTime = parseLongAttribute(parser, ATTR_VALUE);
- break;
- default:
- Slog.e(TAG, "Invalid tag: " + tag);
- break;
}
+ } catch (FileNotFoundException e) {
+ // Use the default
+ } catch (IOException | XmlPullParserException e) {
+ // Remove corrupted file and retry.
+ file.failRead(in, e);
+ loadBaseStateLocked();
+ return;
}
- } catch (FileNotFoundException e) {
- // Use the default
- } catch (IOException | XmlPullParserException e) {
- Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
-
- mRawLastResetTime = 0;
}
// Adjust the last reset time.
getLastResetTimeLocked();
@@ -1067,8 +1082,7 @@ public class ShortcutService extends IShortcutService.Stub {
"user shortcut", null);
}
- @GuardedBy("mLock")
- private void saveUserLocked(@UserIdInt int userId) {
+ private void saveUser(@UserIdInt int userId) {
try (ResilientAtomicFile file = getUserFile(userId)) {
FileOutputStream os = null;
try {
@@ -1076,9 +1090,10 @@ public class ShortcutService extends IShortcutService.Stub {
Slog.d(TAG, "Saving to " + file);
}
- os = file.startWrite();
-
- saveUserInternalLocked(userId, os, /* forBackup= */ false);
+ synchronized (mLock) {
+ os = file.startWrite();
+ saveUserInternalLocked(userId, os, /* forBackup= */ false);
+ }
file.finishWrite(os);
@@ -1215,16 +1230,19 @@ public class ShortcutService extends IShortcutService.Stub {
}
try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "shortcutSaveDirtyInfo");
+ List<Integer> dirtyUserIds = new ArrayList<>();
synchronized (mLock) {
- for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) {
- final int userId = mDirtyUserIds.get(i);
- if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
- saveBaseStateLocked();
- } else {
- saveUserLocked(userId);
- }
+ List<Integer> tmp = mDirtyUserIds;
+ mDirtyUserIds = dirtyUserIds;
+ dirtyUserIds = tmp;
+ }
+ for (int i = dirtyUserIds.size() - 1; i >= 0; i--) {
+ final int userId = dirtyUserIds.get(i);
+ if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
+ saveBaseState();
+ } else {
+ saveUser(userId);
}
- mDirtyUserIds.clear();
}
} catch (Exception e) {
wtf("Exception in saveDirtyInfo", e);
@@ -1237,14 +1255,14 @@ public class ShortcutService extends IShortcutService.Stub {
@GuardedBy("mLock")
long getLastResetTimeLocked() {
updateTimesLocked();
- return mRawLastResetTime;
+ return mRawLastResetTime.get();
}
/** Return the next reset time. */
@GuardedBy("mLock")
long getNextResetTimeLocked() {
updateTimesLocked();
- return mRawLastResetTime + mResetInterval;
+ return mRawLastResetTime.get() + mResetInterval;
}
static boolean isClockValid(long time) {
@@ -1259,25 +1277,26 @@ public class ShortcutService extends IShortcutService.Stub {
final long now = injectCurrentTimeMillis();
- final long prevLastResetTime = mRawLastResetTime;
+ final long prevLastResetTime = mRawLastResetTime.get();
+ long newLastResetTime = prevLastResetTime;
- if (mRawLastResetTime == 0) { // first launch.
+ if (newLastResetTime == 0) { // first launch.
// TODO Randomize??
- mRawLastResetTime = now;
- } else if (now < mRawLastResetTime) {
+ newLastResetTime = now;
+ } else if (now < newLastResetTime) {
// Clock rewound.
if (isClockValid(now)) {
Slog.w(TAG, "Clock rewound");
// TODO Randomize??
- mRawLastResetTime = now;
- }
- } else {
- if ((mRawLastResetTime + mResetInterval) <= now) {
- final long offset = mRawLastResetTime % mResetInterval;
- mRawLastResetTime = ((now / mResetInterval) * mResetInterval) + offset;
+ newLastResetTime = now;
}
+ } else if ((newLastResetTime + mResetInterval) <= now) {
+ final long offset = newLastResetTime % mResetInterval;
+ newLastResetTime = ((now / mResetInterval) * mResetInterval) + offset;
}
- if (prevLastResetTime != mRawLastResetTime) {
+
+ mRawLastResetTime.set(newLastResetTime);
+ if (prevLastResetTime != newLastResetTime) {
scheduleSaveBaseState();
}
}
@@ -2705,9 +2724,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
void resetAllThrottlingInner() {
- synchronized (mLock) {
- mRawLastResetTime = injectCurrentTimeMillis();
- }
+ mRawLastResetTime.set(injectCurrentTimeMillis());
scheduleSaveBaseState();
Slog.i(TAG, "ShortcutManager: throttling counter reset for all users");
}
@@ -2725,8 +2742,8 @@ public class ShortcutService extends IShortcutService.Stub {
}
getPackageShortcutsLocked(packageName, userId)
.resetRateLimitingForCommandLineNoSaving();
- saveUserLocked(userId);
}
+ saveUser(userId);
}
// We override this method in unit tests to do a simpler check.
@@ -4505,8 +4522,8 @@ public class ShortcutService extends IShortcutService.Stub {
dumpCurrentTime(pw);
pw.println();
});
- saveUserLocked(userId);
}
+ saveUser(userId);
}
// === Dump ===
@@ -4717,9 +4734,9 @@ public class ShortcutService extends IShortcutService.Stub {
pw.print(formatTime(now));
pw.print(" Raw last reset: [");
- pw.print(mRawLastResetTime);
+ pw.print(mRawLastResetTime.get());
pw.print("] ");
- pw.print(formatTime(mRawLastResetTime));
+ pw.print(formatTime(mRawLastResetTime.get()));
final long last = getLastResetTimeLocked();
pw.print(" Last reset: [");
diff --git a/services/core/java/com/android/server/pm/UserJourneyLogger.java b/services/core/java/com/android/server/pm/UserJourneyLogger.java
new file mode 100644
index 000000000000..f48a1669c259
--- /dev/null
+++ b/services/core/java/com/android/server/pm/UserJourneyLogger.java
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.os.UserManager.USER_TYPE_FULL_DEMO;
+import static android.os.UserManager.USER_TYPE_FULL_GUEST;
+import static android.os.UserManager.USER_TYPE_FULL_RESTRICTED;
+import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
+import static android.os.UserManager.USER_TYPE_FULL_SYSTEM;
+import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
+import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
+import static android.os.UserManager.USER_TYPE_SYSTEM_HEADLESS;
+
+import static com.android.internal.util.FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNKNOWN;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.pm.UserInfo;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * This class is logging User Lifecycle statsd events and synchronise User Lifecycle Journeys
+ * by making sure all events are called in correct order and errors are reported in case of
+ * unexpected journeys. This class also makes sure that all user sub-journeys are logged so
+ * for example User Switch also log User Start Journey.
+ */
+public class UserJourneyLogger {
+
+ public static final int ERROR_CODE_INVALID_SESSION_ID = 0;
+ public static final int ERROR_CODE_UNSPECIFIED = -1;
+ /*
+ * Possible reasons for ERROR_CODE_INCOMPLETE_OR_TIMEOUT to occur:
+ * - A user switch journey is received while another user switch journey is in
+ * process for the same user.
+ * - A user switch journey is received while user start journey is in process for
+ * the same user.
+ * - A user start journey is received while another user start journey is in process
+ * for the same user.
+ * In all cases potentially an incomplete, timed-out session or multiple
+ * simultaneous requests. It is not possible to keep track of multiple sessions for
+ * the same user, so previous session is abandoned.
+ */
+ public static final int ERROR_CODE_INCOMPLETE_OR_TIMEOUT = 2;
+ public static final int ERROR_CODE_ABORTED = 3;
+ public static final int ERROR_CODE_NULL_USER_INFO = 4;
+ public static final int ERROR_CODE_USER_ALREADY_AN_ADMIN = 5;
+ public static final int ERROR_CODE_USER_IS_NOT_AN_ADMIN = 6;
+
+ @IntDef(prefix = {"ERROR_CODE"}, value = {
+ ERROR_CODE_UNSPECIFIED,
+ ERROR_CODE_INCOMPLETE_OR_TIMEOUT,
+ ERROR_CODE_ABORTED,
+ ERROR_CODE_NULL_USER_INFO,
+ ERROR_CODE_USER_ALREADY_AN_ADMIN,
+ ERROR_CODE_USER_IS_NOT_AN_ADMIN,
+ ERROR_CODE_INVALID_SESSION_ID
+ })
+ public @interface UserJourneyErrorCode {
+ }
+
+ // The various user journeys, defined in the UserLifecycleJourneyReported atom for statsd
+ public static final int USER_JOURNEY_UNKNOWN =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__UNKNOWN;
+ public static final int USER_JOURNEY_USER_SWITCH_FG =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_SWITCH_FG;
+ public static final int USER_JOURNEY_USER_SWITCH_UI =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_SWITCH_UI;
+ public static final int USER_JOURNEY_USER_START =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_START;
+ public static final int USER_JOURNEY_USER_CREATE =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE;
+ public static final int USER_JOURNEY_USER_STOP =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_STOP;
+ public static final int USER_JOURNEY_USER_REMOVE =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_REMOVE;
+ public static final int USER_JOURNEY_GRANT_ADMIN =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN;
+ public static final int USER_JOURNEY_REVOKE_ADMIN =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN;
+
+ @IntDef(prefix = {"USER_JOURNEY"}, value = {
+ USER_JOURNEY_UNKNOWN,
+ USER_JOURNEY_USER_SWITCH_FG,
+ USER_JOURNEY_USER_SWITCH_UI,
+ USER_JOURNEY_USER_START,
+ USER_JOURNEY_USER_STOP,
+ USER_JOURNEY_USER_CREATE,
+ USER_JOURNEY_USER_REMOVE,
+ USER_JOURNEY_GRANT_ADMIN,
+ USER_JOURNEY_REVOKE_ADMIN
+ })
+ public @interface UserJourney {
+ }
+
+
+ // The various user lifecycle events, defined in the UserLifecycleEventOccurred atom for statsd
+ public static final int USER_LIFECYCLE_EVENT_UNKNOWN =
+ USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNKNOWN;
+ public static final int USER_LIFECYCLE_EVENT_SWITCH_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__SWITCH_USER;
+ public static final int USER_LIFECYCLE_EVENT_START_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__START_USER;
+ public static final int USER_LIFECYCLE_EVENT_CREATE_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER;
+ public static final int USER_LIFECYCLE_EVENT_REMOVE_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REMOVE_USER;
+ public static final int USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__USER_RUNNING_LOCKED;
+ public static final int USER_LIFECYCLE_EVENT_UNLOCKING_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNLOCKING_USER;
+ public static final int USER_LIFECYCLE_EVENT_UNLOCKED_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNLOCKED_USER;
+ public static final int USER_LIFECYCLE_EVENT_STOP_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__STOP_USER;
+ public static final int USER_LIFECYCLE_EVENT_GRANT_ADMIN =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__GRANT_ADMIN;
+ public static final int USER_LIFECYCLE_EVENT_REVOKE_ADMIN =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REVOKE_ADMIN;
+
+ @IntDef(prefix = {"USER_LIFECYCLE_EVENT"}, value = {
+ USER_LIFECYCLE_EVENT_UNKNOWN,
+ USER_LIFECYCLE_EVENT_SWITCH_USER,
+ USER_LIFECYCLE_EVENT_START_USER,
+ USER_LIFECYCLE_EVENT_CREATE_USER,
+ USER_LIFECYCLE_EVENT_REMOVE_USER,
+ USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
+ USER_LIFECYCLE_EVENT_UNLOCKING_USER,
+ USER_LIFECYCLE_EVENT_UNLOCKED_USER,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ USER_LIFECYCLE_EVENT_GRANT_ADMIN,
+ USER_LIFECYCLE_EVENT_REVOKE_ADMIN
+ })
+ public @interface UserLifecycleEvent {
+ }
+
+ // User lifecycle event state, defined in the UserLifecycleEventOccurred atom for statsd
+ public static final int EVENT_STATE_BEGIN =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__BEGIN;
+ public static final int EVENT_STATE_FINISH =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__FINISH;
+ public static final int EVENT_STATE_NONE =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__NONE;
+ public static final int EVENT_STATE_CANCEL =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__CANCEL;
+ public static final int EVENT_STATE_ERROR =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__ERROR;
+
+ @IntDef(prefix = {"EVENT_STATE"}, value = {
+ EVENT_STATE_BEGIN,
+ EVENT_STATE_FINISH,
+ EVENT_STATE_NONE,
+ EVENT_STATE_CANCEL,
+ EVENT_STATE_ERROR,
+ })
+ public @interface UserLifecycleEventState {
+ }
+
+ private static final int USER_ID_KEY_MULTIPLICATION = 100;
+
+ private final Object mLock = new Object();
+
+ /**
+ * {@link UserIdInt} and {@link UserJourney} to {@link UserJourneySession} mapping used for
+ * statsd logging for the UserLifecycleJourneyReported and UserLifecycleEventOccurred atoms.
+ */
+ @GuardedBy("mLock")
+ private final SparseArray<UserJourneySession> mUserIdToUserJourneyMap = new SparseArray<>();
+
+ /**
+ * Returns event equivalent of given journey
+ */
+ @UserLifecycleEvent
+ private static int journeyToEvent(@UserJourney int journey) {
+ switch (journey) {
+ case USER_JOURNEY_USER_SWITCH_UI:
+ case USER_JOURNEY_USER_SWITCH_FG:
+ return USER_LIFECYCLE_EVENT_SWITCH_USER;
+ case USER_JOURNEY_USER_START:
+ return USER_LIFECYCLE_EVENT_START_USER;
+ case USER_JOURNEY_USER_CREATE:
+ return USER_LIFECYCLE_EVENT_CREATE_USER;
+ case USER_JOURNEY_USER_STOP:
+ return USER_LIFECYCLE_EVENT_STOP_USER;
+ case USER_JOURNEY_USER_REMOVE:
+ return USER_LIFECYCLE_EVENT_REMOVE_USER;
+ case USER_JOURNEY_GRANT_ADMIN:
+ return USER_LIFECYCLE_EVENT_GRANT_ADMIN;
+ case USER_JOURNEY_REVOKE_ADMIN:
+ return USER_LIFECYCLE_EVENT_REVOKE_ADMIN;
+ default:
+ return USER_LIFECYCLE_EVENT_UNKNOWN;
+ }
+ }
+
+ /**
+ * Returns the enum defined in the statsd UserLifecycleJourneyReported atom corresponding to
+ * the user type.
+ * Changes to this method require changes in CTS file
+ * com.android.cts.packagemanager.stats.device.UserInfoUtil
+ * which is duplicate for CTS tests purposes.
+ */
+ public static int getUserTypeForStatsd(@NonNull String userType) {
+ switch (userType) {
+ case USER_TYPE_FULL_SYSTEM:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SYSTEM;
+ case USER_TYPE_FULL_SECONDARY:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY;
+ case USER_TYPE_FULL_GUEST:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_GUEST;
+ case USER_TYPE_FULL_DEMO:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_DEMO;
+ case USER_TYPE_FULL_RESTRICTED:
+ return FrameworkStatsLog
+ .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_RESTRICTED;
+ case USER_TYPE_PROFILE_MANAGED:
+ return FrameworkStatsLog
+ .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__PROFILE_MANAGED;
+ case USER_TYPE_SYSTEM_HEADLESS:
+ return FrameworkStatsLog
+ .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__SYSTEM_HEADLESS;
+ case USER_TYPE_PROFILE_CLONE:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__PROFILE_CLONE;
+ default:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN;
+ }
+ }
+
+ /**
+ * Map error code to the event finish state.
+ */
+ @UserLifecycleEventState
+ private static int errorToFinishState(@UserJourneyErrorCode int errorCode) {
+ switch (errorCode) {
+ case ERROR_CODE_ABORTED:
+ return EVENT_STATE_CANCEL;
+ case ERROR_CODE_UNSPECIFIED:
+ return EVENT_STATE_FINISH;
+ default:
+ return EVENT_STATE_ERROR;
+ }
+ }
+
+ /**
+ * Simply logging USER_LIFECYCLE_JOURNEY_REPORTED if session exists.
+ * If session does not exist then it logs ERROR_CODE_INVALID_SESSION_ID
+ */
+ @VisibleForTesting
+ public void logUserLifecycleJourneyReported(@Nullable UserJourneySession session,
+ @UserJourney int journey, @UserIdInt int originalUserId, @UserIdInt int targetUserId,
+ int userType, int userFlags, @UserJourneyErrorCode int errorCode) {
+ if (session == null) {
+ writeUserLifecycleJourneyReported(-1, journey, originalUserId, targetUserId,
+ userType, userFlags, ERROR_CODE_INVALID_SESSION_ID);
+ } else {
+ writeUserLifecycleJourneyReported(
+ session.mSessionId, journey, originalUserId, targetUserId, userType, userFlags,
+ errorCode);
+ }
+ }
+
+ /**
+ * Helper method for spy testing
+ */
+ @VisibleForTesting
+ public void writeUserLifecycleJourneyReported(long sessionId, int journey, int originalUserId,
+ int targetUserId, int userType, int userFlags, int errorCode) {
+ FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED,
+ sessionId, journey, originalUserId, targetUserId, userType, userFlags,
+ errorCode);
+ }
+
+ /**
+ * Simply logging USER_LIFECYCLE_EVENT_OCCURRED if session exists.
+ * If session does not exist then it logs ERROR_CODE_INVALID_SESSION_ID
+ * and EVENT_STATE_ERROR
+ */
+ @VisibleForTesting
+ public void logUserLifecycleEventOccurred(UserJourneySession session,
+ @UserIdInt int targetUserId, @UserLifecycleEvent int event,
+ @UserLifecycleEventState int state, @UserJourneyErrorCode int errorCode) {
+ if (session == null) {
+ writeUserLifecycleEventOccurred(-1, targetUserId, event,
+ EVENT_STATE_ERROR, ERROR_CODE_INVALID_SESSION_ID);
+ } else {
+ writeUserLifecycleEventOccurred(session.mSessionId, targetUserId, event, state,
+ errorCode);
+ }
+ }
+
+ /**
+ * Helper method for spy testing
+ */
+ @VisibleForTesting
+ public void writeUserLifecycleEventOccurred(long sessionId, int userId, int event, int state,
+ int errorCode) {
+ FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED,
+ sessionId, userId, event, state, errorCode);
+ }
+
+ /**
+ * statsd helper method for logging the given event for the UserLifecycleEventOccurred statsd
+ * atom. It finds the user journey session for target user id and logs it as that journey.
+ */
+ public void logUserLifecycleEvent(@UserIdInt int userId, @UserLifecycleEvent int event,
+ @UserLifecycleEventState int eventState) {
+ final UserJourneySession userJourneySession = findUserJourneySession(userId);
+ logUserLifecycleEventOccurred(userJourneySession, userId,
+ event, eventState, UserJourneyLogger.ERROR_CODE_UNSPECIFIED);
+ }
+
+ /**
+ * Returns first user session from mUserIdToUserJourneyMap for given user id,
+ * or null if user id was not found in mUserIdToUserJourneyMap.
+ */
+ private @Nullable UserJourneySession findUserJourneySession(@UserIdInt int userId) {
+ synchronized (mLock) {
+ final int keyMapSize = mUserIdToUserJourneyMap.size();
+ for (int i = 0; i < keyMapSize; i++) {
+ int key = mUserIdToUserJourneyMap.keyAt(i);
+ if (key / USER_ID_KEY_MULTIPLICATION == userId) {
+ return mUserIdToUserJourneyMap.get(key);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns unique id for user and journey. For example if user id = 11 and journey = 7
+ * then unique key = 11 * 100 + 7 = 1107
+ */
+ private int getUserJourneyKey(@UserIdInt int targetUserId, @UserJourney int journey) {
+ // We leave 99 for user journeys ids.
+ return (targetUserId * USER_ID_KEY_MULTIPLICATION) + journey;
+ }
+
+ /**
+ * Special use case when user journey incomplete or timeout and current user is unclear
+ */
+ @VisibleForTesting
+ public UserJourneySession finishAndClearIncompleteUserJourney(@UserIdInt int targetUserId,
+ @UserJourney int journey) {
+ synchronized (mLock) {
+ final int key = getUserJourneyKey(targetUserId, journey);
+ final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(key);
+ if (userJourneySession != null) {
+ logUserLifecycleEventOccurred(
+ userJourneySession,
+ targetUserId,
+ journeyToEvent(userJourneySession.mJourney),
+ EVENT_STATE_ERROR,
+ UserJourneyLogger.ERROR_CODE_INCOMPLETE_OR_TIMEOUT);
+
+ logUserLifecycleJourneyReported(
+ userJourneySession,
+ journey,
+ /* originalUserId= */ -1,
+ targetUserId,
+ getUserTypeForStatsd(""), -1,
+ ERROR_CODE_INCOMPLETE_OR_TIMEOUT);
+ mUserIdToUserJourneyMap.remove(key);
+
+ return userJourneySession;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Log user journey event and report finishing without error
+ */
+ public UserJourneySession logUserJourneyFinish(@UserIdInt int originalUserId,
+ UserInfo targetUser, @UserJourney int journey) {
+ return logUserJourneyFinishWithError(originalUserId, targetUser, journey,
+ ERROR_CODE_UNSPECIFIED);
+ }
+
+ /**
+ * Special case when it is unknown which user switch journey was used and checking both
+ */
+ @VisibleForTesting
+ public UserJourneySession logUserSwitchJourneyFinish(@UserIdInt int originalUserId,
+ UserInfo targetUser) {
+ synchronized (mLock) {
+ final int key_fg = getUserJourneyKey(targetUser.id, USER_JOURNEY_USER_SWITCH_FG);
+ final int key_ui = getUserJourneyKey(targetUser.id, USER_JOURNEY_USER_SWITCH_UI);
+
+ if (mUserIdToUserJourneyMap.contains(key_fg)) {
+ return logUserJourneyFinish(originalUserId, targetUser,
+ USER_JOURNEY_USER_SWITCH_FG);
+ }
+
+ if (mUserIdToUserJourneyMap.contains(key_ui)) {
+ return logUserJourneyFinish(originalUserId, targetUser,
+ USER_JOURNEY_USER_SWITCH_UI);
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * Log user journey event and report finishing with error
+ */
+ public UserJourneySession logUserJourneyFinishWithError(@UserIdInt int originalUserId,
+ UserInfo targetUser, @UserJourney int journey, @UserJourneyErrorCode int errorCode) {
+ synchronized (mLock) {
+ final int state = errorToFinishState(errorCode);
+ final int key = getUserJourneyKey(targetUser.id, journey);
+ final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(key);
+ if (userJourneySession != null) {
+ logUserLifecycleEventOccurred(
+ userJourneySession, targetUser.id,
+ journeyToEvent(userJourneySession.mJourney),
+ state,
+ errorCode);
+
+ logUserLifecycleJourneyReported(
+ userJourneySession,
+ journey, originalUserId, targetUser.id,
+ getUserTypeForStatsd(targetUser.userType),
+ targetUser.flags,
+ errorCode);
+ mUserIdToUserJourneyMap.remove(key);
+
+ return userJourneySession;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Log event and report finish when user is null. This is edge case when UserInfo
+ * can not be passed because it is null, therefore all information are passed as arguments.
+ */
+ public UserJourneySession logNullUserJourneyError(@UserJourney int journey,
+ @UserIdInt int currentUserId, @UserIdInt int targetUserId, String targetUserType,
+ int targetUserFlags) {
+ synchronized (mLock) {
+ final int key = getUserJourneyKey(targetUserId, journey);
+ final UserJourneySession session = mUserIdToUserJourneyMap.get(key);
+
+ logUserLifecycleEventOccurred(
+ session, targetUserId, journeyToEvent(journey),
+ EVENT_STATE_ERROR,
+ ERROR_CODE_NULL_USER_INFO);
+
+ logUserLifecycleJourneyReported(
+ session, journey, currentUserId, targetUserId,
+ getUserTypeForStatsd(targetUserType), targetUserFlags,
+ ERROR_CODE_NULL_USER_INFO);
+
+ mUserIdToUserJourneyMap.remove(key);
+ return session;
+ }
+ }
+
+ /**
+ * Log for user creation finish event and report. This is edge case when target user id is
+ * different in begin event and finish event as it is unknown what is user id
+ * until it has been created.
+ */
+ public UserJourneySession logUserCreateJourneyFinish(@UserIdInt int originalUserId,
+ UserInfo targetUser) {
+ synchronized (mLock) {
+ // we do not know user id until we create new user which is why we use -1
+ // as user id to create and find session, but we log correct id.
+ final int key = getUserJourneyKey(-1, USER_JOURNEY_USER_CREATE);
+ final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(key);
+ if (userJourneySession != null) {
+ logUserLifecycleEventOccurred(
+ userJourneySession, targetUser.id,
+ USER_LIFECYCLE_EVENT_CREATE_USER,
+ EVENT_STATE_FINISH,
+ ERROR_CODE_UNSPECIFIED);
+
+ logUserLifecycleJourneyReported(
+ userJourneySession,
+ USER_JOURNEY_USER_CREATE, originalUserId, targetUser.id,
+ getUserTypeForStatsd(targetUser.userType),
+ targetUser.flags,
+ ERROR_CODE_UNSPECIFIED);
+ mUserIdToUserJourneyMap.remove(key);
+
+ return userJourneySession;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds new UserJourneySession to mUserIdToUserJourneyMap and log UserJourneyEvent Begin state
+ */
+ public UserJourneySession logUserJourneyBegin(@UserIdInt int targetId,
+ @UserJourney int journey) {
+ final long newSessionId = ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE);
+ synchronized (mLock) {
+ final int key = getUserJourneyKey(targetId, journey);
+ final UserJourneySession userJourneySession =
+ new UserJourneySession(newSessionId, journey);
+ mUserIdToUserJourneyMap.append(key, userJourneySession);
+
+ logUserLifecycleEventOccurred(
+ userJourneySession, targetId,
+ journeyToEvent(userJourneySession.mJourney),
+ EVENT_STATE_BEGIN,
+ ERROR_CODE_UNSPECIFIED);
+
+ return userJourneySession;
+ }
+ }
+
+ /**
+ * Helper class to store user journey and session id.
+ *
+ * <p> User journey tracks a chain of user lifecycle events occurring during different user
+ * activities such as user start, user switch, and user creation.
+ */
+ public static class UserJourneySession {
+ public final long mSessionId;
+ @UserJourney
+ public final int mJourney;
+
+ @VisibleForTesting
+ public UserJourneySession(long sessionId, @UserJourney int journey) {
+ mJourney = journey;
+ mSessionId = sessionId;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5f8efe29459d..b92cdde5910f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -23,6 +23,15 @@ import static android.os.UserManager.DISALLOW_USER_SWITCH;
import static android.os.UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY;
import static android.os.UserManager.USER_OPERATION_ERROR_UNKNOWN;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_ABORTED;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_UNSPECIFIED;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_ALREADY_AN_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_IS_NOT_AN_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_GRANT_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_REVOKE_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_CREATE;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_REMOVE;
+
import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
@@ -162,7 +171,6 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -519,6 +527,8 @@ public class UserManagerService extends IUserManager.Stub {
@GuardedBy("mUserLifecycleListeners")
private final ArrayList<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
+ private final UserJourneyLogger mUserJourneyLogger = new UserJourneyLogger();
+
private final LockPatternUtils mLockPatternUtils;
private final String ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK =
@@ -1580,45 +1590,56 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public void setUserAdmin(@UserIdInt int userId) {
checkManageUserAndAcrossUsersFullPermission("set user admin");
- final long sessionId = logGrantAdminJourneyBegin(userId);
+ mUserJourneyLogger.logUserJourneyBegin(userId, USER_JOURNEY_GRANT_ADMIN);
UserInfo info;
synchronized (mPackagesLock) {
synchronized (mUsersLock) {
info = getUserInfoLU(userId);
}
- if (info == null || info.isAdmin()) {
- // Exit if no user found with that id, or the user is already an Admin.
- logUserJourneyError(sessionId,
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN,
- userId);
+ if (info == null) {
+ // Exit if no user found with that id,
+ mUserJourneyLogger.logNullUserJourneyError(USER_JOURNEY_GRANT_ADMIN,
+ getCurrentUserId(), userId, /* userType */ "", /* userFlags */ -1);
+ return;
+ } else if (info.isAdmin()) {
+ // Exit if the user is already an Admin.
+ mUserJourneyLogger.logUserJourneyFinishWithError(getCurrentUserId(), info,
+ USER_JOURNEY_GRANT_ADMIN, ERROR_CODE_USER_ALREADY_AN_ADMIN);
return;
}
info.flags ^= UserInfo.FLAG_ADMIN;
writeUserLP(getUserDataLU(info.id));
}
- logGrantAdminJourneyFinish(sessionId, userId, info.userType, info.flags);
+ mUserJourneyLogger.logUserJourneyFinishWithError(getCurrentUserId(), info,
+ USER_JOURNEY_GRANT_ADMIN, ERROR_CODE_UNSPECIFIED);
}
@Override
public void revokeUserAdmin(@UserIdInt int userId) {
checkManageUserAndAcrossUsersFullPermission("revoke admin privileges");
- final long sessionId = logRevokeAdminJourneyBegin(userId);
+ mUserJourneyLogger.logUserJourneyBegin(userId, USER_JOURNEY_REVOKE_ADMIN);
UserData user;
synchronized (mPackagesLock) {
synchronized (mUsersLock) {
user = getUserDataLU(userId);
- if (user == null || !user.info.isAdmin()) {
- // Exit if no user found with that id, or the user is not an Admin.
- logUserJourneyError(sessionId, FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN,
- userId);
+ if (user == null) {
+ // Exit if no user found with that id
+ mUserJourneyLogger.logNullUserJourneyError(
+ USER_JOURNEY_REVOKE_ADMIN,
+ getCurrentUserId(), userId, "", -1);
+ return;
+ } else if (!user.info.isAdmin()) {
+ // Exit if no user is not an Admin.
+ mUserJourneyLogger.logUserJourneyFinishWithError(getCurrentUserId(), user.info,
+ USER_JOURNEY_REVOKE_ADMIN, ERROR_CODE_USER_IS_NOT_AN_ADMIN);
return;
}
user.info.flags ^= UserInfo.FLAG_ADMIN;
writeUserLP(user);
}
}
- logRevokeAdminJourneyFinish(sessionId, userId, user.info.userType, user.info.flags);
+ mUserJourneyLogger.logUserJourneyFinishWithError(getCurrentUserId(), user.info,
+ USER_JOURNEY_REVOKE_ADMIN, ERROR_CODE_UNSPECIFIED);
}
/**
@@ -4700,16 +4721,20 @@ public class UserManagerService extends IUserManager.Stub {
final int noneUserId = -1;
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("createUser-" + flags);
- final long sessionId = logUserCreateJourneyBegin(noneUserId);
+ mUserJourneyLogger.logUserJourneyBegin(noneUserId, USER_JOURNEY_USER_CREATE);
UserInfo newUser = null;
try {
newUser = createUserInternalUncheckedNoTracing(name, userType, flags, parentId,
preCreate, disallowedPackages, t, token);
return newUser;
} finally {
- logUserCreateJourneyFinish(sessionId,
- newUser != null ? newUser.id : noneUserId, userType, flags,
- newUser != null);
+ if (newUser != null) {
+ mUserJourneyLogger.logUserCreateJourneyFinish(getCurrentUserId(), newUser);
+ } else {
+ mUserJourneyLogger.logNullUserJourneyError(
+ USER_JOURNEY_USER_CREATE,
+ getCurrentUserId(), noneUserId, userType, flags);
+ }
t.traceEnd();
}
}
@@ -5198,137 +5223,6 @@ public class UserManagerService extends IUserManager.Stub {
&& !userTypeDetails.getName().equals(UserManager.USER_TYPE_FULL_RESTRICTED);
}
- private long logUserCreateJourneyBegin(@UserIdInt int userId) {
- return logUserJourneyBegin(
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE,
- userId);
- }
-
- private void logUserCreateJourneyFinish(long sessionId, @UserIdInt int userId, String userType,
- @UserInfoFlag int flags, boolean finish) {
- logUserJourneyFinish(sessionId,
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE,
- userId, userType, flags, finish);
- }
-
- private long logUserRemoveJourneyBegin(@UserIdInt int userId) {
- return logUserJourneyBegin(
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_REMOVE,
- userId);
- }
-
- private void logUserRemoveJourneyFinish(long sessionId, @UserIdInt int userId, String userType,
- @UserInfoFlag int flags, boolean finish) {
- logUserJourneyFinish(sessionId,
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_REMOVE,
- userId, userType, flags, finish);
- }
-
- private long logGrantAdminJourneyBegin(@UserIdInt int userId) {
- return logUserJourneyBegin(
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN,
- userId);
- }
-
- private void logGrantAdminJourneyFinish(long sessionId, @UserIdInt int userId, String userType,
- @UserInfoFlag int flags) {
- logUserJourneyFinish(sessionId,
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN,
- userId, userType, flags, true);
- }
-
- private long logRevokeAdminJourneyBegin(@UserIdInt int userId) {
- return logUserJourneyBegin(
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN,
- userId);
- }
-
- private void logRevokeAdminJourneyFinish(long sessionId, @UserIdInt int userId, String userType,
- @UserInfoFlag int flags) {
- logUserJourneyFinish(sessionId,
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN,
- userId, userType, flags, true);
- }
-
- private void logUserJourneyFinish(long sessionId, int journey, @UserIdInt int userId,
- String userType, @UserInfoFlag int flags, boolean finish) {
-
- // log the journey atom with the user metadata
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED, sessionId,
- journey, /* origin_user= */ getCurrentUserId(), userId,
- UserManager.getUserTypeForStatsd(userType), flags);
-
- int event;
- switch (journey) {
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_REMOVE:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REMOVE_USER;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__GRANT_ADMIN;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REVOKE_ADMIN;
- break;
- default:
- throw new IllegalArgumentException("Journey " + journey + " not expected.");
- }
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId,
- event,
- finish ? FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__FINISH
- : FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__NONE);
- }
-
- private long logUserJourneyBegin(int journey, @UserIdInt int userId) {
- final long sessionId = ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE);
-
- // log the event atom to indicate the event start
- int event;
- switch (journey) {
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_REMOVE:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REMOVE_USER;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__GRANT_ADMIN;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REVOKE_ADMIN;
- break;
- default:
- throw new IllegalArgumentException("Journey " + journey + " not expected.");
- }
-
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId,
- event, FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__BEGIN);
- return sessionId;
- }
-
- private void logUserJourneyError(long sessionId, int journey, @UserIdInt int userId) {
-
- // log the journey atom with the user metadata
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED, sessionId,
- journey, /* origin_user= */ getCurrentUserId(), userId);
-
- int event;
- switch (journey) {
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__GRANT_ADMIN;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REVOKE_ADMIN;
- break;
- default:
- throw new IllegalArgumentException("Journey " + journey + " not expected.");
- }
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId,
- event, FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__ERROR);
- }
-
/** Register callbacks for statsd pulled atoms. */
private void registerStatsCallbacks() {
final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
@@ -5352,7 +5246,8 @@ public class UserManagerService extends IUserManager.Stub {
if (size > 1) {
for (int idx = 0; idx < size; idx++) {
final UserInfo user = users.get(idx);
- final int userTypeStandard = UserManager.getUserTypeForStatsd(user.userType);
+ final int userTypeStandard = mUserJourneyLogger
+ .getUserTypeForStatsd(user.userType);
final String userTypeCustom = (userTypeStandard == FrameworkStatsLog
.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN)
?
@@ -5635,7 +5530,7 @@ public class UserManagerService extends IUserManager.Stub {
writeUserLP(userData);
}
- final long sessionId = logUserRemoveJourneyBegin(userId);
+ mUserJourneyLogger.logUserJourneyBegin(userId, USER_JOURNEY_USER_REMOVE);
try {
mAppOpsService.removeUser(userId);
@@ -5657,13 +5552,17 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public void userStopped(int userIdParam) {
finishRemoveUser(userIdParam);
- logUserRemoveJourneyFinish(sessionId, userIdParam,
- userData.info.userType, userData.info.flags, true);
+ int originUserId = UserManagerService.this.getCurrentUserId();
+ mUserJourneyLogger.logUserJourneyFinishWithError(originUserId,
+ userData.info, USER_JOURNEY_USER_REMOVE,
+ ERROR_CODE_UNSPECIFIED);
}
@Override
public void userStopAborted(int userIdParam) {
- logUserRemoveJourneyFinish(sessionId, userIdParam,
- userData.info.userType, userData.info.flags, false);
+ int originUserId = UserManagerService.this.getCurrentUserId();
+ mUserJourneyLogger.logUserJourneyFinishWithError(originUserId,
+ userData.info, USER_JOURNEY_USER_REMOVE,
+ ERROR_CODE_ABORTED);
}
});
} catch (RemoteException e) {
@@ -7297,9 +7196,9 @@ public class UserManagerService extends IUserManager.Stub {
final UserInfo userInfo = getUserInfo(userIds[i]);
if (userInfo == null) {
// Not possible because the input user ids should all be valid
- userTypes[i] = UserManager.getUserTypeForStatsd("");
+ userTypes[i] = mUserJourneyLogger.getUserTypeForStatsd("");
} else {
- userTypes[i] = UserManager.getUserTypeForStatsd(userInfo.userType);
+ userTypes[i] = mUserJourneyLogger.getUserTypeForStatsd(userInfo.userType);
}
}
return userTypes;
@@ -7536,4 +7435,11 @@ public class UserManagerService extends IUserManager.Stub {
.getBoolean(R.bool.config_canSwitchToHeadlessSystemUser);
}
+ /**
+ * Returns instance of {@link com.android.server.pm.UserJourneyLogger}.
+ */
+ public UserJourneyLogger getUserJourneyLogger() {
+ return mUserJourneyLogger;
+ }
+
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9ff98be6f5cd..f8954b7c7f95 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5690,8 +5690,14 @@ public final class PowerManagerService extends SystemService
}
if (eventTime > now) {
- Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
- throw new IllegalArgumentException("event time must not be in the future");
+ Slog.wtf(TAG, "Event cannot be newer than the current time ("
+ + "now=" + now
+ + ", eventTime=" + eventTime
+ + ", displayId=" + displayId
+ + ", event=" + PowerManager.userActivityEventToString(event)
+ + ", flags=" + flags
+ + ")");
+ return;
}
final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index f971db9b5f0e..e796275c53e3 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -161,7 +161,13 @@ public class TrustAgentWrapper {
mDisplayTrustGrantedMessage = (flags & FLAG_GRANT_TRUST_DISPLAY_MESSAGE) != 0;
if ((flags & FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0) {
mWaitingForTrustableDowngrade = true;
- setSecurityWindowTimer();
+ resultCallback.thenAccept(result -> {
+ if (result.getStatus() == GrantTrustResult.STATUS_UNLOCKED_BY_GRANT) {
+ // if we are not unlocked by grantTrust, then we don't need to
+ // have the timer for the security window
+ setSecurityWindowTimer();
+ }
+ });
} else {
mWaitingForTrustableDowngrade = false;
}
@@ -562,6 +568,7 @@ public class TrustAgentWrapper {
* @see android.service.trust.TrustAgentService#onDeviceLocked()
*/
public void onDeviceLocked() {
+ mWithinSecurityLockdownWindow = false;
try {
if (mTrustAgentService != null) mTrustAgentService.onDeviceLocked();
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 8786005d519f..1ab982399b57 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -393,6 +393,23 @@ public class TrustManagerService extends SystemService {
true /* overrideHardTimeout */);
}
+ private void cancelBothTrustableAlarms(int userId) {
+ TrustableTimeoutAlarmListener idleTimeout =
+ mIdleTrustableTimeoutAlarmListenerForUser.get(
+ userId);
+ TrustableTimeoutAlarmListener trustableTimeout =
+ mTrustableTimeoutAlarmListenerForUser.get(
+ userId);
+ if (idleTimeout != null && idleTimeout.isQueued()) {
+ idleTimeout.setQueued(false);
+ mAlarmManager.cancel(idleTimeout);
+ }
+ if (trustableTimeout != null && trustableTimeout.isQueued()) {
+ trustableTimeout.setQueued(false);
+ mAlarmManager.cancel(trustableTimeout);
+ }
+ }
+
private void handleScheduleTrustedTimeout(int userId, boolean shouldOverride) {
long when = SystemClock.elapsedRealtime() + TRUST_TIMEOUT_IN_MILLIS;
TrustedTimeoutAlarmListener alarm = mTrustTimeoutAlarmListenerForUser.get(userId);
@@ -657,6 +674,11 @@ public class TrustManagerService extends SystemService {
resultCallback.complete(new GrantTrustResult(STATUS_UNLOCKED_BY_GRANT));
}
}
+
+ if ((wasTrusted || wasTrustable) && pendingTrustState == TrustState.UNTRUSTED) {
+ if (DEBUG) Slog.d(TAG, "Trust was revoked, destroy trustable alarms");
+ cancelBothTrustableAlarms(userId);
+ }
}
private void updateTrustUsuallyManaged(int userId, boolean managed) {
@@ -1908,7 +1930,11 @@ public class TrustManagerService extends SystemService {
handleScheduleTrustTimeout(shouldOverride, timeoutType);
break;
case MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH:
- refreshTrustableTimers(msg.arg1);
+ TrustableTimeoutAlarmListener trustableAlarm =
+ mTrustableTimeoutAlarmListenerForUser.get(msg.arg1);
+ if (trustableAlarm != null && trustableAlarm.isQueued()) {
+ refreshTrustableTimers(msg.arg1);
+ }
break;
}
}
@@ -2160,7 +2186,7 @@ public class TrustManagerService extends SystemService {
TrustedTimeoutAlarmListener otherAlarm;
boolean otherAlarmPresent;
if (ENABLE_ACTIVE_UNLOCK_FLAG) {
- cancelBothTrustableAlarms();
+ cancelBothTrustableAlarms(mUserId);
otherAlarm = mTrustTimeoutAlarmListenerForUser.get(mUserId);
otherAlarmPresent = (otherAlarm != null) && otherAlarm.isQueued();
if (otherAlarmPresent) {
@@ -2172,23 +2198,6 @@ public class TrustManagerService extends SystemService {
}
}
- private void cancelBothTrustableAlarms() {
- TrustableTimeoutAlarmListener idleTimeout =
- mIdleTrustableTimeoutAlarmListenerForUser.get(
- mUserId);
- TrustableTimeoutAlarmListener trustableTimeout =
- mTrustableTimeoutAlarmListenerForUser.get(
- mUserId);
- if (idleTimeout != null && idleTimeout.isQueued()) {
- idleTimeout.setQueued(false);
- mAlarmManager.cancel(idleTimeout);
- }
- if (trustableTimeout != null && trustableTimeout.isQueued()) {
- trustableTimeout.setQueued(false);
- mAlarmManager.cancel(trustableTimeout);
- }
- }
-
private void disableRenewableTrustWhileNonrenewableTrustIsPresent() {
// if non-renewable trust is running, we need to temporarily prevent
// renewable trust from being used
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 9020cb3405a2..45c7c9ad4477 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2445,12 +2445,36 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
/**
* TODO(multi-display) Extends this method with specific display.
- * Propagate ambient state to wallpaper engine.
+ * Propagate ambient state to wallpaper engine(s).
*
* @param inAmbientMode {@code true} when in ambient mode, {@code false} otherwise.
* @param animationDuration Duration of the animation, or 0 when immediate.
*/
public void setInAmbientMode(boolean inAmbientMode, long animationDuration) {
+ if (mIsLockscreenLiveWallpaperEnabled) {
+ List<IWallpaperEngine> engines = new ArrayList<>();
+ synchronized (mLock) {
+ mInAmbientMode = inAmbientMode;
+ for (WallpaperData data : getActiveWallpapers()) {
+ if (data.connection.mInfo == null
+ || data.connection.mInfo.supportsAmbientMode()) {
+ // TODO(multi-display) Extends this method with specific display.
+ IWallpaperEngine engine = data.connection
+ .getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
+ if (engine != null) engines.add(engine);
+ }
+ }
+ }
+ for (IWallpaperEngine engine : engines) {
+ try {
+ engine.setInAmbientMode(inAmbientMode, animationDuration);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to set ambient mode", e);
+ }
+ }
+ return;
+ }
+
final IWallpaperEngine engine;
synchronized (mLock) {
mInAmbientMode = inAmbientMode;
@@ -2475,10 +2499,25 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
/**
- * Propagate a wake event to the wallpaper engine.
+ * Propagate a wake event to the wallpaper engine(s).
*/
public void notifyWakingUp(int x, int y, @NonNull Bundle extras) {
synchronized (mLock) {
+ if (mIsLockscreenLiveWallpaperEnabled) {
+ for (WallpaperData data : getActiveWallpapers()) {
+ data.connection.forEachDisplayConnector(displayConnector -> {
+ if (displayConnector.mEngine != null) {
+ try {
+ displayConnector.mEngine.dispatchWallpaperCommand(
+ WallpaperManager.COMMAND_WAKING_UP, x, y, -1, extras);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to dispatch COMMAND_WAKING_UP", e);
+ }
+ }
+ });
+ }
+ return;
+ }
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
if (data != null && data.connection != null) {
data.connection.forEachDisplayConnector(
@@ -2497,10 +2536,26 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
/**
- * Propagate a sleep event to the wallpaper engine.
+ * Propagate a sleep event to the wallpaper engine(s).
*/
public void notifyGoingToSleep(int x, int y, @NonNull Bundle extras) {
synchronized (mLock) {
+ if (mIsLockscreenLiveWallpaperEnabled) {
+ for (WallpaperData data : getActiveWallpapers()) {
+ data.connection.forEachDisplayConnector(displayConnector -> {
+ if (displayConnector.mEngine != null) {
+ try {
+ displayConnector.mEngine.dispatchWallpaperCommand(
+ WallpaperManager.COMMAND_GOING_TO_SLEEP, x, y, -1,
+ extras);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to dispatch COMMAND_GOING_TO_SLEEP", e);
+ }
+ }
+ });
+ }
+ return;
+ }
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
if (data != null && data.connection != null) {
data.connection.forEachDisplayConnector(
@@ -2520,11 +2575,27 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
/**
- * Propagates screen turned on event to wallpaper engine.
+ * Propagates screen turned on event to wallpaper engine(s).
*/
@Override
public void notifyScreenTurnedOn(int displayId) {
synchronized (mLock) {
+ if (mIsLockscreenLiveWallpaperEnabled) {
+ for (WallpaperData data : getActiveWallpapers()) {
+ if (data.connection.containsDisplay(displayId)) {
+ final IWallpaperEngine engine = data.connection
+ .getDisplayConnectorOrCreate(displayId).mEngine;
+ if (engine != null) {
+ try {
+ engine.onScreenTurnedOn();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to notify that the screen turned on", e);
+ }
+ }
+ }
+ }
+ return;
+ }
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
if (data != null
&& data.connection != null
@@ -2545,11 +2616,27 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
/**
- * Propagate screen turning on event to wallpaper engine.
+ * Propagate screen turning on event to wallpaper engine(s).
*/
@Override
public void notifyScreenTurningOn(int displayId) {
synchronized (mLock) {
+ if (mIsLockscreenLiveWallpaperEnabled) {
+ for (WallpaperData data : getActiveWallpapers()) {
+ if (data.connection.containsDisplay(displayId)) {
+ final IWallpaperEngine engine = data.connection
+ .getDisplayConnectorOrCreate(displayId).mEngine;
+ if (engine != null) {
+ try {
+ engine.onScreenTurningOn();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to notify that the screen is turning on", e);
+ }
+ }
+ }
+ }
+ return;
+ }
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
if (data != null
&& data.connection != null
@@ -2576,6 +2663,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
return true;
}
+ private WallpaperData[] getActiveWallpapers() {
+ WallpaperData systemWallpaper = mWallpaperMap.get(mCurrentUserId);
+ WallpaperData lockWallpaper = mLockWallpaperMap.get(mCurrentUserId);
+ boolean systemValid = systemWallpaper != null && systemWallpaper.connection != null;
+ boolean lockValid = lockWallpaper != null && lockWallpaper.connection != null;
+ return systemValid && lockValid ? new WallpaperData[]{systemWallpaper, lockWallpaper}
+ : systemValid ? new WallpaperData[]{systemWallpaper}
+ : lockValid ? new WallpaperData[]{lockWallpaper}
+ : new WallpaperData[0];
+ }
+
private IWallpaperEngine getEngine(int which, int userId, int displayId) {
WallpaperData wallpaperData = findWallpaperAtDisplay(userId, displayId);
if (wallpaperData == null) return null;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c3cd3eca84f2..26b40b4c09ee 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -582,6 +582,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean mPauseSchedulePendingForPip = false;
+ // Gets set to indicate that the activity is currently being auto-pipped.
+ boolean mAutoEnteringPip = false;
+
private void updateEnterpriseThumbnailDrawable(Context context) {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
mEnterpriseThumbnailDrawable = dpm.getResources().getDrawable(
@@ -4908,9 +4911,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mTransitionController.setStatusBarTransitionDelay(
mPendingRemoteAnimation.getStatusBarTransitionDelay());
} else {
- if (mPendingOptions == null
- || mPendingOptions.getAnimationType() == ANIM_SCENE_TRANSITION) {
- // Scene transition will run on the client side.
+ if (mPendingOptions == null) {
+ return;
+ } else if (mPendingOptions.getAnimationType() == ANIM_SCENE_TRANSITION) {
+ // Scene transition will run on the client side, so just notify transition
+ // controller but don't clear the animation information from the options since they
+ // need to be sent to the animating activity.
+ mTransitionController.setOverrideAnimation(
+ AnimationOptions.makeSceneTransitionAnimOptions(), null, null);
return;
}
applyOptionsAnimation(mPendingOptions, intent);
@@ -5220,6 +5228,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
logAppCompatState();
if (!visible) {
+ final InputTarget imeInputTarget = mDisplayContent.getImeInputTarget();
+ mLastImeShown = imeInputTarget != null && imeInputTarget.getWindowState() != null
+ && imeInputTarget.getWindowState().mActivityRecord == this
+ && mDisplayContent.mInputMethodWindow != null
+ && mDisplayContent.mInputMethodWindow.isVisible();
finishOrAbortReplacingWindow();
}
return true;
@@ -5609,11 +5622,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
if (!visible) {
- final InputTarget imeInputTarget = mDisplayContent.getImeInputTarget();
- mLastImeShown = imeInputTarget != null && imeInputTarget.getWindowState() != null
- && imeInputTarget.getWindowState().mActivityRecord == this
- && mDisplayContent.mInputMethodWindow != null
- && mDisplayContent.mInputMethodWindow.isVisible();
mImeInsetsFrozenUntilStartInput = true;
}
@@ -6094,8 +6102,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
PauseActivityItem.obtain(finishing, false /* userLeaving */,
- configChangeFlags, false /* dontReport */,
- false /* autoEnteringPip */));
+ configChangeFlags, false /* dontReport */, mAutoEnteringPip));
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index bfe298653584..a6e50405e7d9 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -45,6 +45,7 @@ import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
@@ -554,7 +555,25 @@ public class ActivityStartController {
.execute();
}
+ /**
+ * A quick path (skip general intent/task resolving) to start recents animation if the recents
+ * (or home) activity is available in background.
+ * @return {@code true} if the recents activity is moved to front.
+ */
boolean startExistingRecentsIfPossible(Intent intent, ActivityOptions options) {
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startExistingRecents");
+ if (startExistingRecents(intent, options)) {
+ return true;
+ }
+ // Else follow the standard launch procedure.
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ return false;
+ }
+
+ private boolean startExistingRecents(Intent intent, ActivityOptions options) {
final int activityType = mService.getRecentTasks().getRecentsComponent()
.equals(intent.getComponent()) ? ACTIVITY_TYPE_RECENTS : ACTIVITY_TYPE_HOME;
final Task rootTask = mService.mRootWindowContainer.getDefaultTaskDisplayArea()
@@ -563,6 +582,7 @@ public class ActivityStartController {
final ActivityRecord r = rootTask.topRunningActivity();
if (r == null || r.isVisibleRequested() || !r.attachedToProcess()
|| !r.mActivityComponent.equals(intent.getComponent())
+ || !mService.isCallerRecents(r.getUid())
// Recents keeps invisible while device is locked.
|| r.mDisplayContent.isKeyguardLocked()) {
return false;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a27f3e49457d..19a12f2b9cc0 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1468,9 +1468,8 @@ class ActivityStarter {
// transition based on a sub-action.
// Only do the create here (and defer requestStart) since startActivityInner might abort.
final TransitionController transitionController = r.mTransitionController;
- Transition newTransition = (!transitionController.isCollecting()
- && transitionController.getTransitionPlayer() != null)
- ? transitionController.createTransition(TRANSIT_OPEN) : null;
+ Transition newTransition = transitionController.isShellTransitionsEnabled()
+ ? transitionController.createAndStartCollecting(TRANSIT_OPEN) : null;
RemoteTransition remoteTransition = r.takeRemoteTransition();
try {
mService.deferWindowLayout();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 1f4606b09396..b816dad2a62e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3592,15 +3592,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
+ boolean enterPictureInPictureMode(@NonNull ActivityRecord r,
+ @NonNull PictureInPictureParams params, boolean fromClient) {
+ return enterPictureInPictureMode(r, params, fromClient, false /* isAutoEnter */);
+ }
+
/**
* Puts the given activity in picture in picture mode if possible.
*
* @param fromClient true if this comes from a client call (eg. Activity.enterPip).
+ * @param isAutoEnter true if this comes from an automatic pip-enter.
* @return true if the activity is now in picture-in-picture mode, or false if it could not
* enter picture-in-picture mode.
*/
boolean enterPictureInPictureMode(@NonNull ActivityRecord r,
- @NonNull PictureInPictureParams params, boolean fromClient) {
+ @NonNull PictureInPictureParams params, boolean fromClient, boolean isAutoEnter) {
// If the activity is already in picture in picture mode, then just return early
if (r.inPinnedWindowingMode()) {
return true;
@@ -3635,6 +3641,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return;
}
r.setPictureInPictureParams(params);
+ r.mAutoEnteringPip = isAutoEnter;
mRootWindowContainer.moveActivityToPinnedRootTask(r,
null /* launchIntoPipHostActivity */, "enterPictureInPictureMode",
transition);
@@ -3643,6 +3650,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
r.getTask().schedulePauseActivity(r, false /* userLeaving */,
false /* pauseImmediately */, true /* autoEnteringPip */, "auto-pip");
}
+ r.mAutoEnteringPip = false;
}
};
@@ -5753,23 +5761,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
BackgroundStartPrivileges backgroundStartPrivileges) {
assertPackageMatchesCallingUid(callingPackage);
- // A quick path (skip general intent/task resolving) to start recents animation if the
- // recents (or home) activity is available in background.
- if (options != null && options.getOriginalOptions() != null
- && options.getOriginalOptions().getTransientLaunch() && isCallerRecents(uid)) {
- try {
- synchronized (mGlobalLock) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "startExistingRecents");
- if (mActivityStartController.startExistingRecentsIfPossible(
- intent, options.getOriginalOptions())) {
- return ActivityManager.START_TASK_TO_FRONT;
- }
- // Else follow the standard launch procedure.
- }
- } finally {
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- }
return getActivityStartController().startActivityInPackage(uid, realCallingPid,
realCallingUid, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, options, userId, inTask,
@@ -6345,6 +6336,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public void cleanupDisabledPackageComponents(
String packageName, Set<String> disabledClasses, int userId, boolean booted) {
synchronized (mGlobalLock) {
+ // In case if setWindowManager hasn't been called yet when booting.
+ if (mRootWindowContainer == null) return;
// Clean-up disabled activities.
if (mRootWindowContainer.finishDisabledPackageActivities(
packageName, disabledClasses, true /* doit */, false /* evenPersistent */,
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 7a11120132bd..7e783938d30a 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -267,7 +267,12 @@ class AsyncRotationController extends FadeAnimationController implements Consume
op.mDrawTransaction = null;
if (DEBUG) Slog.d(TAG, "finishOp merge transaction " + windowToken.getTopChild());
}
- if (op.mAction == Operation.ACTION_FADE) {
+ if (op.mAction == Operation.ACTION_TOGGLE_IME) {
+ if (DEBUG) Slog.d(TAG, "finishOp fade-in IME " + windowToken.getTopChild());
+ fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM,
+ (type, anim) -> mDisplayContent.getInsetsStateController()
+ .getImeSourceProvider().reportImeDrawnForOrganizer());
+ } else if (op.mAction == Operation.ACTION_FADE) {
if (DEBUG) Slog.d(TAG, "finishOp fade-in " + windowToken.getTopChild());
// The previous animation leash will be dropped when preparing fade-in animation, so
// simply apply new animation without restoring the transformation.
@@ -344,7 +349,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
final WindowToken windowToken = mTargetWindowTokens.keyAt(i);
final Operation op = mTargetWindowTokens.valueAt(i);
- if (op.mAction == Operation.ACTION_FADE) {
+ if (op.mAction == Operation.ACTION_FADE || op.mAction == Operation.ACTION_TOGGLE_IME) {
fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
op.mLeash = windowToken.getAnimationLeash();
if (DEBUG) Slog.d(TAG, "Start fade-out " + windowToken.getTopChild());
@@ -374,17 +379,19 @@ class AsyncRotationController extends FadeAnimationController implements Consume
WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION);
}
- /** Hides the window immediately until it is drawn in new rotation. */
- void hideImmediately(WindowToken windowToken) {
- if (isTargetToken(windowToken)) return;
+ /** Hides the IME window immediately until it is drawn in new rotation. */
+ void hideImeImmediately() {
+ if (mDisplayContent.mInputMethodWindow == null) return;
+ final WindowToken imeWindowToken = mDisplayContent.mInputMethodWindow.mToken;
+ if (isTargetToken(imeWindowToken)) return;
final boolean original = mHideImmediately;
mHideImmediately = true;
- final Operation op = new Operation(Operation.ACTION_FADE);
- mTargetWindowTokens.put(windowToken, op);
- fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
- op.mLeash = windowToken.getAnimationLeash();
+ final Operation op = new Operation(Operation.ACTION_TOGGLE_IME);
+ mTargetWindowTokens.put(imeWindowToken, op);
+ fadeWindowToken(false /* show */, imeWindowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
+ op.mLeash = imeWindowToken.getAnimationLeash();
mHideImmediately = original;
- if (DEBUG) Slog.d(TAG, "hideImmediately " + windowToken.getTopChild());
+ if (DEBUG) Slog.d(TAG, "hideImeImmediately " + imeWindowToken.getTopChild());
}
/** Returns {@code true} if the window will rotate independently. */
@@ -586,11 +593,13 @@ class AsyncRotationController extends FadeAnimationController implements Consume
/** The operation to control the rotation appearance associated with window token. */
private static class Operation {
@Retention(RetentionPolicy.SOURCE)
- @IntDef(value = { ACTION_SEAMLESS, ACTION_FADE })
+ @IntDef(value = { ACTION_SEAMLESS, ACTION_FADE, ACTION_TOGGLE_IME })
@interface Action {}
static final int ACTION_SEAMLESS = 1;
static final int ACTION_FADE = 2;
+ /** The action to toggle the IME window appearance */
+ static final int ACTION_TOGGLE_IME = 3;
final @Action int mAction;
/** The leash of window token. It can be animation leash or the token itself. */
SurfaceControl mLeash;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8bca1067de8c..57812c1d604c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1896,7 +1896,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
case SOFT_INPUT_STATE_HIDDEN:
return false;
}
- return r.mLastImeShown;
+ final boolean useIme = r.getWindow(
+ w -> WindowManager.LayoutParams.mayUseInputMethod(w.mAttrs.flags)) != null;
+ if (!useIme) {
+ return false;
+ }
+ return r.mLastImeShown || (r.mStartingData != null && r.mStartingData.hasImeSurface());
}
/** Returns {@code true} if the top activity is transformed with the new rotation of display. */
@@ -4219,7 +4224,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Hide the window until the rotation is done to avoid intermediate artifacts if the
// parent surface of IME container is changed.
if (mAsyncRotationController != null) {
- mAsyncRotationController.hideImmediately(mInputMethodWindow.mToken);
+ mAsyncRotationController.hideImeImmediately();
}
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index ce4362853b23..be52e5a4566b 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1095,11 +1095,9 @@ public class DisplayPolicy {
} else {
overrideProviders = null;
}
- final @InsetsType int type = provider.getType();
- final int id = InsetsSource.createId(
- provider.getOwner(), provider.getIndex(), type);
- mDisplayContent.getInsetsStateController().getOrCreateSourceProvider(id, type)
- .setWindowContainer(win, frameProvider, overrideProviders);
+ mDisplayContent.getInsetsStateController().getOrCreateSourceProvider(
+ provider.getId(), provider.getType()).setWindowContainer(
+ win, frameProvider, overrideProviders);
mInsetsSourceWindowsExceptIme.add(win);
}
}
diff --git a/services/core/java/com/android/server/wm/FadeAnimationController.java b/services/core/java/com/android/server/wm/FadeAnimationController.java
index 561a07061bb4..7af67e63f469 100644
--- a/services/core/java/com/android/server/wm/FadeAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeAnimationController.java
@@ -57,14 +57,21 @@ public class FadeAnimationController {
return AnimationUtils.loadAnimation(mContext, R.anim.fade_out);
}
+ /** Run the fade in/out animation for a window token. */
+ public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
+ fadeWindowToken(show, windowToken, animationType, null);
+ }
+
/**
* Run the fade in/out animation for a window token.
*
* @param show true for fade-in, otherwise for fade-out.
* @param windowToken the window token to run the animation.
* @param animationType the animation type defined in SurfaceAnimator.
+ * @param finishedCallback the callback after the animation finished.
*/
- public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
+ public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType,
+ SurfaceAnimator.OnAnimationFinishedCallback finishedCallback) {
if (windowToken == null || windowToken.getParent() == null) {
return;
}
@@ -75,9 +82,8 @@ public class FadeAnimationController {
if (animationAdapter == null) {
return;
}
-
windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
- show /* hidden */, animationType, null /* finishedCallback */);
+ show /* hidden */, animationType, finishedCallback);
}
protected FadeAnimationAdapter createAdapter(LocalAnimationAdapter.AnimationSpec animationSpec,
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index b4dffdcba243..ff2985c98421 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -145,18 +145,44 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider {
}
boolean changed = super.updateClientVisibility(caller);
if (changed && caller.isRequestedVisible(mSource.getType())) {
- reportImeDrawnForOrganizer(caller);
+ reportImeDrawnForOrganizerIfNeeded(caller);
}
changed |= mDisplayContent.onImeInsetsClientVisibilityUpdate();
return changed;
}
- private void reportImeDrawnForOrganizer(InsetsControlTarget caller) {
- if (caller.getWindow() != null && caller.getWindow().getTask() != null) {
- if (caller.getWindow().getTask().isOrganized()) {
- mWindowContainer.mWmService.mAtmService.mTaskOrganizerController
- .reportImeDrawnOnTask(caller.getWindow().getTask());
- }
+ private void reportImeDrawnForOrganizerIfNeeded(@NonNull InsetsControlTarget caller) {
+ final WindowState callerWindow = caller.getWindow();
+ if (callerWindow == null) {
+ return;
+ }
+ WindowToken imeToken = mWindowContainer.asWindowState() != null
+ ? mWindowContainer.asWindowState().mToken : null;
+ if (mDisplayContent.getAsyncRotationController() != null
+ && mDisplayContent.getAsyncRotationController().isTargetToken(imeToken)) {
+ // Skip reporting IME drawn state when the control target is in fixed
+ // rotation, AsyncRotationController will report after the animation finished.
+ return;
+ }
+ reportImeDrawnForOrganizer(caller);
+ }
+
+ private void reportImeDrawnForOrganizer(@NonNull InsetsControlTarget caller) {
+ final WindowState callerWindow = caller.getWindow();
+ if (callerWindow == null || callerWindow.getTask() == null) {
+ return;
+ }
+ if (callerWindow.getTask().isOrganized()) {
+ mWindowContainer.mWmService.mAtmService.mTaskOrganizerController
+ .reportImeDrawnOnTask(caller.getWindow().getTask());
+ }
+ }
+
+ /** Report the IME has drawn on the current IME control target for its task organizer */
+ void reportImeDrawnForOrganizer() {
+ final InsetsControlTarget imeControlTarget = getControlTarget();
+ if (imeControlTarget != null) {
+ reportImeDrawnForOrganizer(imeControlTarget);
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index fe13b87a079a..ddf96c53323d 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -311,16 +311,13 @@ class InsetsPolicy {
state.removeSource(ID_IME);
} else if (attrs.providedInsets != null) {
for (InsetsFrameProvider provider : attrs.providedInsets) {
- final int id = InsetsSource.createId(
- provider.getOwner(), provider.getIndex(), provider.getType());
- final @InsetsType int type = provider.getType();
- if ((type & WindowInsets.Type.systemBars()) == 0) {
+ if ((provider.getType() & WindowInsets.Type.systemBars()) == 0) {
continue;
}
if (state == originalState) {
state = new InsetsState(state);
}
- state.removeSource(id);
+ state.removeSource(provider.getId());
}
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 08a6358afbc7..5f6d66011768 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -269,6 +269,8 @@ class KeyguardController {
TRANSIT_TO_BACK, transitFlags, null /* trigger */, dc);
updateKeyguardSleepToken();
+ // Make the home wallpaper visible
+ dc.mWallpaperController.showHomeWallpaperInTransition();
// Some stack visibility might change (e.g. docked stack)
mRootWindowContainer.resumeFocusedTasksTopActivities();
mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index b5df3e0937ec..bbb85636f1ee 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -193,6 +193,7 @@ class ScreenRotationAnimation {
.setSourceCrop(new Rect(0, 0, width, height))
.setAllowProtected(true)
.setCaptureSecureLayers(true)
+ .setHintForSeamlessTransition(true)
.build();
screenshotBuffer = ScreenCapture.captureDisplay(captureArgs);
} else {
@@ -202,6 +203,7 @@ class ScreenRotationAnimation {
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.setSourceCrop(new Rect(0, 0, width, height))
+ .setHintForSeamlessTransition(true)
.build();
screenshotBuffer = ScreenCapture.captureLayers(captureArgs);
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 5626aa7f075f..cdb4ad645dc3 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -18,6 +18,9 @@ package com.android.server.wm;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.TaskInfo.cameraCompatControlStateToString;
+import static android.window.StartingWindowRemovalInfo.DEFER_MODE_NONE;
+import static android.window.StartingWindowRemovalInfo.DEFER_MODE_NORMAL;
+import static android.window.StartingWindowRemovalInfo.DEFER_MODE_ROTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
@@ -686,8 +689,19 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
final boolean playShiftUpAnimation = !task.inMultiWindowMode();
final ActivityRecord topActivity = task.topActivityContainsStartingWindow();
if (topActivity != null) {
- removalInfo.deferRemoveForIme = topActivity.mDisplayContent
- .mayImeShowOnLaunchingActivity(topActivity);
+ // Set defer remove mode for IME
+ final DisplayContent dc = topActivity.getDisplayContent();
+ final WindowState imeWindow = dc.mInputMethodWindow;
+ if (topActivity.isVisibleRequested() && imeWindow != null
+ && dc.mayImeShowOnLaunchingActivity(topActivity)
+ && dc.isFixedRotationLaunchingApp(topActivity)) {
+ removalInfo.deferRemoveForImeMode = DEFER_MODE_ROTATION;
+ } else if (dc.mayImeShowOnLaunchingActivity(topActivity)) {
+ removalInfo.deferRemoveForImeMode = DEFER_MODE_NORMAL;
+ } else {
+ removalInfo.deferRemoveForImeMode = DEFER_MODE_NONE;
+ }
+
final WindowState mainWindow =
topActivity.findMainWindow(false/* includeStartingApp */);
// No app window for this activity, app might be crashed.
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 0f74aebc2fde..50bf38b8ce16 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -607,9 +607,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
recordDisplay(wc.getDisplayContent());
if (info.mShowWallpaper) {
// Collect the wallpaper token (for isWallpaper(wc)) so it is part of the sync set.
- final WindowState wallpaper =
- wc.getDisplayContent().mWallpaperController.getTopVisibleWallpaper();
- if (wallpaper != null) {
+ final List<WindowState> wallpapers =
+ wc.getDisplayContent().mWallpaperController.getAllTopWallpapers();
+ for (int i = wallpapers.size() - 1; i >= 0; i--) {
+ WindowState wallpaper = wallpapers.get(i);
collect(wallpaper.mToken);
}
}
@@ -954,8 +955,15 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
// to the transient activity.
ar.supportsEnterPipOnTaskSwitch = true;
}
+ // Make sure this activity can enter pip under the current circumstances.
+ // `enterPictureInPicture` internally checks, but with beforeStopping=false which
+ // is specifically for non-auto-enter.
+ if (!ar.checkEnterPictureInPictureState("enterPictureInPictureMode",
+ true /* beforeStopping */)) {
+ return false;
+ }
return mController.mAtm.enterPictureInPictureMode(ar, ar.pictureInPictureArgs,
- false /* fromClient */);
+ false /* fromClient */, true /* isAutoEnter */);
}
// Legacy pip-entry (not via isAutoEnterEnabled).
@@ -1317,6 +1325,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
// ActivityRecord#canShowWindows() may reject to show its window. The visibility also
// needs to be updated for STATE_ABORT.
commitVisibleActivities(transaction);
+ commitVisibleWallpapers();
// Fall-back to the default display if there isn't one participating.
final DisplayContent primaryDisplay = !mTargetDisplays.isEmpty() ? mTargetDisplays.get(0)
@@ -1349,6 +1358,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
}
// Resolve the animating targets from the participants.
mTargets = calculateTargets(mParticipants, mChanges);
+
// Check whether the participants were animated from back navigation.
mController.mAtm.mBackNavigationController.onTransactionReady(this, mTargets);
final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction);
@@ -1625,6 +1635,30 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
}
}
+ /**
+ * Reset waitingToshow for all wallpapers, and commit the visibility of the visible ones
+ */
+ private void commitVisibleWallpapers() {
+ boolean showWallpaper = shouldWallpaperBeVisible();
+ for (int i = mParticipants.size() - 1; i >= 0; --i) {
+ final WallpaperWindowToken wallpaper = mParticipants.valueAt(i).asWallpaperToken();
+ if (wallpaper != null) {
+ wallpaper.waitingToShow = false;
+ if (!wallpaper.isVisible() && wallpaper.isVisibleRequested()) {
+ wallpaper.commitVisibility(showWallpaper);
+ }
+ }
+ }
+ }
+
+ private boolean shouldWallpaperBeVisible() {
+ for (int i = mParticipants.size() - 1; i >= 0; --i) {
+ WindowContainer participant = mParticipants.valueAt(i);
+ if (participant.showWallpaper()) return true;
+ }
+ return false;
+ }
+
// TODO(b/188595497): Remove after migrating to shell.
/** @see RecentsAnimationController#attachNavigationBarToApp */
private void handleLegacyRecentsStartBehavior(DisplayContent dc, TransitionInfo info) {
@@ -2233,7 +2267,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
// Display won't be rotated for multi window Task, so the fixed rotation
// won't be applied. This can happen when the windowing mode is changed
// before the previous fixed rotation is applied.
- && !task.inMultiWindowMode()) {
+ && (!task.inMultiWindowMode() || !topRunningActivity.inMultiWindowMode())) {
// If Activity is in fixed rotation, its will be applied with the next rotation,
// when the Task is still in the previous rotation.
final int taskRotation = task.getWindowConfiguration().getDisplayRotation();
@@ -2999,11 +3033,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
Rect cropBounds = new Rect(bounds);
cropBounds.offsetTo(0, 0);
+ final boolean isDisplayRotation = wc.asDisplayContent() != null
+ && wc.asDisplayContent().isRotationChanging();
ScreenCapture.LayerCaptureArgs captureArgs =
new ScreenCapture.LayerCaptureArgs.Builder(wc.getSurfaceControl())
.setSourceCrop(cropBounds)
.setCaptureSecureLayers(true)
.setAllowProtected(true)
+ .setHintForSeamlessTransition(isDisplayRotation)
.build();
ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
ScreenCapture.captureLayers(captureArgs);
@@ -3014,8 +3051,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
Slog.w(TAG, "Failed to capture screenshot for " + wc);
return false;
}
- final boolean isDisplayRotation = wc.asDisplayContent() != null
- && wc.asDisplayContent().isRotationChanging();
// Some tests may check the name "RotationLayer" to detect display rotation.
final String name = isDisplayRotation ? "RotationLayer" : "transition snapshot: " + wc;
SurfaceControl snapshotSurface = wc.makeAnimationLeash()
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index e1da91a6cb21..c9316bf6e972 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -813,6 +813,10 @@ class TransitionController {
}
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Finish Transition: %s", record);
mPlayingTransitions.remove(record);
+ if (!inTransition()) {
+ // reset track-count now since shell-side is idle.
+ mTrackCount = 0;
+ }
updateRunningRemoteAnimation(record, false /* isPlaying */);
record.finishTransition();
for (int i = mAnimatingExitWindows.size() - 1; i >= 0; i--) {
@@ -825,10 +829,9 @@ class TransitionController {
}
}
mRunningLock.doNotifyLocked();
- // Run state-validation checks when no transitions are active anymore.
+ // Run state-validation checks when no transitions are active anymore (Note: sometimes
+ // finish can start a transition, so check afterwards -- eg. pip).
if (!inTransition()) {
- // Can reset track-count now that everything is idle.
- mTrackCount = 0;
validateStates();
mAtm.mWindowManager.onAnimationFinished();
}
@@ -874,7 +877,7 @@ class TransitionController {
tryStartCollectFromQueue();
}
- private boolean canStartCollectingNow(Transition queued) {
+ private boolean canStartCollectingNow(@Nullable Transition queued) {
if (mCollectingTransition == null) return true;
// Population (collect until ready) is still serialized, so always wait for that.
if (!mCollectingTransition.isPopulated()) return false;
@@ -947,14 +950,14 @@ class TransitionController {
* `collecting` transition. It may still ultimately block in sync-engine or become dependent
* in {@link #getIsIndependent} later.
*/
- boolean getCanBeIndependent(Transition collecting, Transition queued) {
+ boolean getCanBeIndependent(Transition collecting, @Nullable Transition queued) {
// For tests
- if (queued.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL
+ if (queued != null && queued.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL
&& collecting.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL) {
return true;
}
// For recents
- if (queued.mParallelCollectType == Transition.PARALLEL_TYPE_RECENTS) {
+ if (queued != null && queued.mParallelCollectType == Transition.PARALLEL_TYPE_RECENTS) {
if (collecting.mParallelCollectType == Transition.PARALLEL_TYPE_RECENTS) {
// Must serialize with itself.
return false;
@@ -1251,6 +1254,44 @@ class TransitionController {
return true;
}
+ /**
+ * This will create and start collecting for a transition if possible. If there's no way to
+ * start collecting for `parallelType` now, then this returns null.
+ *
+ * WARNING: ONLY use this if the transition absolutely cannot be deferred!
+ */
+ @NonNull
+ Transition createAndStartCollecting(int type) {
+ if (mTransitionPlayer == null) {
+ return null;
+ }
+ if (!mQueuedTransitions.isEmpty()) {
+ // There is a queue, so it's not possible to start immediately
+ return null;
+ }
+ if (mSyncEngine.hasActiveSync()) {
+ if (isCollecting()) {
+ // Check if we can run in parallel here.
+ if (canStartCollectingNow(null /* transit */)) {
+ // create and collect in parallel.
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Moving #%d from"
+ + " collecting to waiting.", mCollectingTransition.getSyncId());
+ mWaitingTransitions.add(mCollectingTransition);
+ mCollectingTransition = null;
+ Transition transit = new Transition(type, 0 /* flags */, this, mSyncEngine);
+ moveToCollecting(transit);
+ return transit;
+ }
+ } else {
+ Slog.w(TAG, "Ongoing Sync outside of transition.");
+ }
+ return null;
+ }
+ Transition transit = new Transition(type, 0 /* flags */, this, mSyncEngine);
+ moveToCollecting(transit);
+ return transit;
+ }
+
/** Returns {@code true} if it started collecting, {@code false} if it was queued. */
boolean startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Runnable applySync) {
if (!mQueuedTransitions.isEmpty() || mSyncEngine.hasActiveSync()) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 7ceac4fe7f16..edafe0606b13 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -124,24 +124,19 @@ class WallpaperController {
final boolean mIsLockscreenLiveWallpaperEnabled;
- private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> {
- if ((w.mAttrs.type == TYPE_WALLPAPER)) {
- if (mFindResults.topWallpaper == null || mFindResults.resetTopWallpaper) {
- WallpaperWindowToken token = w.mToken.asWallpaperToken();
- if (token == null) {
- Slog.w(TAG, "Window " + w + " has wallpaper type but not wallpaper token");
- return false;
- }
- if (!token.canShowWhenLocked() && mDisplayContent.isKeyguardLocked()) {
- return false;
- }
- mFindResults.setTopWallpaper(w);
- mFindResults.resetTopWallpaper = false;
+ private final Consumer<WindowState> mFindWallpapers = w -> {
+ if (w.mAttrs.type == TYPE_WALLPAPER) {
+ WallpaperWindowToken token = w.mToken.asWallpaperToken();
+ if (token.canShowWhenLocked() && !mFindResults.hasTopShowWhenLockedWallpaper()) {
+ mFindResults.setTopShowWhenLockedWallpaper(w);
+ } else if (!token.canShowWhenLocked()
+ && !mFindResults.hasTopHideWhenLockedWallpaper()) {
+ mFindResults.setTopHideWhenLockedWallpaper(w);
}
- return false;
}
+ };
- mFindResults.resetTopWallpaper = true;
+ private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> {
if (!w.mTransitionController.isShellTransitionsEnabled()) {
if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
&& !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
@@ -344,6 +339,31 @@ class WallpaperController {
}
}
+ /**
+ * Change the visibility if wallpaper is home screen only.
+ * This is called during the keyguard unlocking transition
+ * (see {@link KeyguardController#keyguardGoingAway(int, int)}) and thus assumes that if the
+ * system wallpaper is shared with lock, then it needs no animation.
+ */
+ public void showHomeWallpaperInTransition() {
+ updateWallpaperWindowsTarget(mFindResults);
+
+ if (!mFindResults.hasTopShowWhenLockedWallpaper()) {
+ Slog.w(TAG, "There is no wallpaper for the lock screen");
+ return;
+ }
+ WindowState hideWhenLocked = mFindResults.mTopWallpaper.mTopHideWhenLockedWallpaper;
+ WindowState showWhenLocked = mFindResults.mTopWallpaper.mTopShowWhenLockedWallpaper;
+ if (!mFindResults.hasTopHideWhenLockedWallpaper()) {
+ // Shared wallpaper, ensure its visibility
+ showWhenLocked.mToken.asWallpaperToken().updateWallpaperWindows(true);
+ } else {
+ // Separate lock and home wallpapers: show home wallpaper and hide lock
+ hideWhenLocked.mToken.asWallpaperToken().updateWallpaperWindowsInTransition(true);
+ showWhenLocked.mToken.asWallpaperToken().updateWallpaperWindowsInTransition(false);
+ }
+ }
+
void hideDeferredWallpapersIfNeededLegacy() {
for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
final WallpaperWindowToken token = mWallpaperTokens.get(i);
@@ -668,13 +688,26 @@ class WallpaperController {
mFindResults.setUseTopWallpaperAsTarget(true);
}
+ mDisplayContent.forAllWindows(mFindWallpapers, true /* traverseTopToBottom */);
mDisplayContent.forAllWindows(mFindWallpaperTargetFunction, true /* traverseTopToBottom */);
if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) {
- mFindResults.setWallpaperTarget(mFindResults.topWallpaper);
+ mFindResults.setWallpaperTarget(
+ mFindResults.getTopWallpaper(mDisplayContent.isKeyguardLocked()));
}
}
+ List<WindowState> getAllTopWallpapers() {
+ ArrayList<WindowState> wallpapers = new ArrayList<>(2);
+ if (mFindResults.hasTopShowWhenLockedWallpaper()) {
+ wallpapers.add(mFindResults.mTopWallpaper.mTopShowWhenLockedWallpaper);
+ }
+ if (mFindResults.hasTopHideWhenLockedWallpaper()) {
+ wallpapers.add(mFindResults.mTopWallpaper.mTopHideWhenLockedWallpaper);
+ }
+ return wallpapers;
+ }
+
private boolean isFullscreen(WindowManager.LayoutParams attrs) {
return attrs.x == 0 && attrs.y == 0
&& attrs.width == MATCH_PARENT && attrs.height == MATCH_PARENT;
@@ -760,10 +793,16 @@ class WallpaperController {
result.setWallpaperTarget(wallpaperTarget);
}
+ /**
+ * Change the visibility of the top wallpaper to {@param visibility} and hide all the others.
+ */
private void updateWallpaperTokens(boolean visibility, boolean locked) {
+ WindowState topWallpaper = mFindResults.getTopWallpaper(locked);
+ WallpaperWindowToken topWallpaperToken =
+ topWallpaper == null ? null : topWallpaper.mToken.asWallpaperToken();
for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
- token.updateWallpaperWindows(visibility && (!locked || token.canShowWhenLocked()));
+ token.updateWallpaperWindows(visibility && (token == topWallpaperToken));
}
}
@@ -801,8 +840,10 @@ class WallpaperController {
}
}
- // Keep both wallpapers visible unless the keyguard is locked (then hide private wp)
- updateWallpaperTokens(visible, mDisplayContent.isKeyguardLocked());
+ if (!mDisplayContent.isKeyguardGoingAway() || !mIsLockscreenLiveWallpaperEnabled) {
+ // When keyguard goes away, KeyguardController handles the visibility
+ updateWallpaperTokens(visible, mDisplayContent.isKeyguardLocked());
+ }
if (DEBUG_WALLPAPER) {
Slog.v(TAG, "adjustWallpaperWindows: wallpaper visibility " + visible
@@ -1019,14 +1060,52 @@ class WallpaperController {
/** Helper class for storing the results of a wallpaper target find operation. */
final private static class FindWallpaperTargetResult {
- WindowState topWallpaper = null;
+
+ static final class TopWallpaper {
+ // A wp that can be visible on home screen only
+ WindowState mTopHideWhenLockedWallpaper = null;
+ // A wallpaper that has permission to be visible on lock screen (lock or shared wp)
+ WindowState mTopShowWhenLockedWallpaper = null;
+
+ void reset() {
+ mTopHideWhenLockedWallpaper = null;
+ mTopShowWhenLockedWallpaper = null;
+ }
+ }
+
+ TopWallpaper mTopWallpaper = new TopWallpaper();
boolean useTopWallpaperAsTarget = false;
WindowState wallpaperTarget = null;
- boolean resetTopWallpaper = false;
boolean isWallpaperTargetForLetterbox = false;
- void setTopWallpaper(WindowState win) {
- topWallpaper = win;
+ void setTopHideWhenLockedWallpaper(WindowState win) {
+ if (DEBUG_WALLPAPER) {
+ Slog.v(TAG, "setTopHideWhenLockedWallpaper " + win);
+ }
+ mTopWallpaper.mTopHideWhenLockedWallpaper = win;
+ }
+
+ void setTopShowWhenLockedWallpaper(WindowState win) {
+ if (DEBUG_WALLPAPER) {
+ Slog.v(TAG, "setTopShowWhenLockedWallpaper " + win);
+ }
+ mTopWallpaper.mTopShowWhenLockedWallpaper = win;
+ }
+
+ boolean hasTopHideWhenLockedWallpaper() {
+ return mTopWallpaper.mTopHideWhenLockedWallpaper != null;
+ }
+
+ boolean hasTopShowWhenLockedWallpaper() {
+ return mTopWallpaper.mTopShowWhenLockedWallpaper != null;
+ }
+
+ WindowState getTopWallpaper(boolean isKeyguardLocked) {
+ if (!isKeyguardLocked && hasTopHideWhenLockedWallpaper()) {
+ return mTopWallpaper.mTopHideWhenLockedWallpaper;
+ } else {
+ return mTopWallpaper.mTopShowWhenLockedWallpaper;
+ }
}
void setWallpaperTarget(WindowState win) {
@@ -1042,10 +1121,9 @@ class WallpaperController {
}
void reset() {
- topWallpaper = null;
+ mTopWallpaper.reset();
wallpaperTarget = null;
useTopWallpaperAsTarget = false;
- resetTopWallpaper = false;
isWallpaperTargetForLetterbox = false;
}
}
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 1ffee05d20ec..5ea8f65b759c 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -128,6 +128,20 @@ class WallpaperWindowToken extends WindowToken {
}
}
+ /**
+ * Update the visibility of the token to {@param visible}. If a transition will collect the
+ * wallpaper, then the visibility will be committed during the execution of the transition.
+ *
+ * waitingToShow is reset at the beginning of the transition:
+ * {@link Transition#onTransactionReady(int, SurfaceControl.Transaction)}
+ */
+ void updateWallpaperWindowsInTransition(boolean visible) {
+ if (mTransitionController.isCollecting() && mVisibleRequested != visible) {
+ waitingToShow = true;
+ }
+ updateWallpaperWindows(visible);
+ }
+
void updateWallpaperWindows(boolean visible) {
if (mVisibleRequested != visible) {
ProtoLog.d(WM_DEBUG_WALLPAPER, "Wallpaper token %s visible=%b",
@@ -199,11 +213,11 @@ class WallpaperWindowToken extends WindowToken {
}
/**
- * Commits the visibility of this token. This will directly update the visibility without
- * regard for other state (like being in a transition).
+ * Commits the visibility of this token. This will directly update the visibility unless the
+ * wallpaper is in a transition.
*/
void commitVisibility(boolean visible) {
- if (visible == isVisible()) return;
+ if (visible == isVisible() || waitingToShow) return;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"commitVisibility: %s: visible=%b mVisibleRequested=%b", this,
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index a5cdd0b43eb0..3ccf183920d3 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -435,8 +435,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
if (mLocalInsetsSources == null) {
mLocalInsetsSources = new SparseArray<>();
}
- final int id = InsetsSource.createId(
- provider.getOwner(), provider.getIndex(), provider.getType());
+ final int id = provider.getId();
if (mLocalInsetsSources.get(id) != null) {
if (DEBUG) {
Slog.d(TAG, "The local insets source for this " + provider
@@ -457,8 +456,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return;
}
- final int id = InsetsSource.createId(
- provider.getOwner(), provider.getIndex(), provider.getType());
+ final int id = provider.getId();
if (mLocalInsetsSources.get(id) == null) {
if (DEBUG) {
Slog.d(TAG, "Given " + provider + " doesn't have a local insets source.");
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f9b6fc10360d..40c6c464f433 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3915,8 +3915,9 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent == null) {
- throw new IllegalStateException("No touch mode is defined for displayId {"
- + displayId + "}");
+ throw new IllegalStateException("Failed to retrieve the touch mode state for"
+ + "display {" + displayId + "}: display is not registered in "
+ + "WindowRootContainer");
}
return displayContent.isInTouchMode();
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index d5aa520e1b6e..09312bac593f 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -972,19 +972,30 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
switch (type) {
case HIERARCHY_OP_TYPE_PENDING_INTENT: {
+ final Bundle launchOpts = hop.getLaunchOptions();
+ ActivityOptions activityOptions = launchOpts != null
+ ? new ActivityOptions(launchOpts) : null;
+ if (activityOptions != null && activityOptions.getTransientLaunch()
+ && mService.isCallerRecents(hop.getPendingIntent().getCreatorUid())) {
+ if (mService.getActivityStartController().startExistingRecentsIfPossible(
+ hop.getActivityIntent(), activityOptions)) {
+ // Start recents successfully.
+ break;
+ }
+ }
+
String resolvedType = hop.getActivityIntent() != null
? hop.getActivityIntent().resolveTypeIfNeeded(
mService.mContext.getContentResolver())
: null;
- ActivityOptions activityOptions = null;
if (hop.getPendingIntent().isActivity()) {
// Set the context display id as preferred for this activity launches, so that
// it can land on caller's display. Or just brought the task to front at the
// display where it was on since it has higher preference.
- activityOptions = hop.getLaunchOptions() != null
- ? new ActivityOptions(hop.getLaunchOptions())
- : ActivityOptions.makeBasic();
+ if (activityOptions == null) {
+ activityOptions = ActivityOptions.makeBasic();
+ }
activityOptions.setCallerDisplayId(DEFAULT_DISPLAY);
}
final Bundle options = activityOptions != null ? activityOptions.toBundle() : null;
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 4af685e42246..0488247ec78b 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -561,6 +561,14 @@ static jstring com_android_server_am_CachedAppOptimizer_getFreezerCheckPath(JNIE
return env->NewStringUTF(path.c_str());
}
+static jboolean com_android_server_am_CachedAppOptimizer_isFreezerProfileValid(JNIEnv* env) {
+ int uid = getuid();
+ int pid = getpid();
+
+ return isProfileValidForProcess("Frozen", uid, pid) &&
+ isProfileValidForProcess("Unfrozen", uid, pid);
+}
+
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"cancelCompaction", "()V",
@@ -578,7 +586,9 @@ static const JNINativeMethod sMethods[] = {
{"getBinderFreezeInfo", "(I)I",
(void*)com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo},
{"getFreezerCheckPath", "()Ljava/lang/String;",
- (void*)com_android_server_am_CachedAppOptimizer_getFreezerCheckPath}};
+ (void*)com_android_server_am_CachedAppOptimizer_getFreezerCheckPath},
+ {"isFreezerProfileValid", "()Z",
+ (void*)com_android_server_am_CachedAppOptimizer_isFreezerProfileValid}};
int register_android_server_am_CachedAppOptimizer(JNIEnv* env)
{
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index 19a0c5e8adcb..04ecd6ebd2d1 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -67,7 +67,7 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
.createNewSession(mContext, mUserId, providerInfo,
this, remoteCredentialService);
if (providerClearSession != null) {
- Slog.d(TAG, "In startProviderSession - provider session created "
+ Slog.i(TAG, "Provider session created "
+ "and being added for: " + providerInfo.getComponentName());
mProviders.put(providerClearSession.getComponentName().flattenToString(),
providerClearSession);
@@ -78,12 +78,12 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
@Override // from provider session
public void onProviderStatusChanged(ProviderSession.Status status,
ComponentName componentName, ProviderSession.CredentialsSource source) {
- Slog.d(TAG, "in onStatusChanged with status: " + status + ", and source: " + source);
+ Slog.i(TAG, "Provider changed with status: " + status + ", and source: " + source);
if (ProviderSession.isTerminatingStatus(status)) {
- Slog.d(TAG, "in onProviderStatusChanged terminating status");
+ Slog.i(TAG, "Provider terminating status");
onProviderTerminated(componentName);
} else if (ProviderSession.isCompletionStatus(status)) {
- Slog.d(TAG, "in onProviderStatusChanged isCompletionStatus status");
+ Slog.i(TAG, "Provider has completion status");
onProviderResponseComplete(componentName);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index b073ff400e44..4b3206242d77 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -79,7 +79,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
.createNewSession(mContext, mUserId, providerInfo,
this, remoteCredentialService);
if (providerCreateSession != null) {
- Slog.d(TAG, "In initiateProviderSession - provider session created and "
+ Slog.i(TAG, "Provider session created and "
+ "being added for: " + providerInfo.getComponentName());
mProviders.put(providerCreateSession.getComponentName().flattenToString(),
providerCreateSession);
@@ -127,7 +127,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
@Override
public void onFinalResponseReceived(ComponentName componentName,
@Nullable CreateCredentialResponse response) {
- Slog.d(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString());
+ Slog.i(TAG, "Final credential received from: " + componentName.flattenToString());
mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime());
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(mProviders.get(
componentName.flattenToString()).mProviderSessionMetric
@@ -170,13 +170,13 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
@Override
public void onProviderStatusChanged(ProviderSession.Status status,
ComponentName componentName, ProviderSession.CredentialsSource source) {
- Slog.d(TAG, "in onStatusChanged with status: " + status + ", and source: " + source);
+ Slog.i(TAG, "Provider status changed: " + status + ", and source: " + source);
// If all provider responses have been received, we can either need the UI,
// or we need to respond with error. The only other case is the entry being
// selected after the UI has been invoked which has a separate code path.
if (!isAnyProviderPending()) {
if (isUiInvocationNeeded()) {
- Slog.d(TAG, "in onProviderStatusChanged - isUiInvocationNeeded");
+ Slog.i(TAG, "Provider status changed - ui invocation is needed");
getProviderDataAndInitiateUi();
} else {
respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS,
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 06b96eb46ac1..7f95e058406e 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -58,7 +58,6 @@ import android.provider.Settings;
import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialProviderInfoFactory;
import android.text.TextUtils;
-import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -437,7 +436,7 @@ public final class CredentialManagerService
IGetCredentialCallback callback,
final String callingPackage) {
final long timestampBegan = System.nanoTime();
- Slog.d(TAG, "starting executeGetCredential with callingPackage: "
+ Slog.i(TAG, "starting executeGetCredential with callingPackage: "
+ callingPackage);
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
@@ -472,7 +471,7 @@ public final class CredentialManagerService
GetCredentialException.TYPE_NO_CREDENTIAL,
"No credentials available on this device.");
} catch (RemoteException e) {
- Log.i(
+ Slog.e(
TAG,
"Issue invoking onError on IGetCredentialCallback "
+ "callback: "
@@ -528,7 +527,7 @@ public final class CredentialManagerService
false, null,
false, false, null));
} catch (RemoteException e) {
- Log.i(
+ Slog.e(
TAG,
"Issue invoking onError on IGetCredentialCallback "
+ "callback: "
@@ -607,7 +606,7 @@ public final class CredentialManagerService
ICreateCredentialCallback callback,
String callingPackage) {
final long timestampBegan = System.nanoTime();
- Slog.d(TAG, "starting executeCreateCredential with callingPackage: "
+ Slog.i(TAG, "starting executeCreateCredential with callingPackage: "
+ callingPackage);
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
@@ -673,7 +672,7 @@ public final class CredentialManagerService
MetricUtilities.logApiCalledInitialPhase(initMetric,
session.mRequestSessionMetric.returnIncrementSequence());
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: ", e);
+ Slog.i(TAG, "Unexpected error during metric logging: ", e);
}
}
@@ -706,7 +705,7 @@ public final class CredentialManagerService
Settings.Secure.CREDENTIAL_SERVICE,
storedValue,
userId)) {
- Log.e(TAG, "Failed to store setting containing enabled providers");
+ Slog.e(TAG, "Failed to store setting containing enabled providers");
try {
callback.onError(
"failed_setting_store",
@@ -733,7 +732,7 @@ public final class CredentialManagerService
@Override
public boolean isEnabledCredentialProviderService(
ComponentName componentName, String callingPackage) {
- Slog.d(TAG, "isEnabledCredentialProviderService with componentName: "
+ Slog.i(TAG, "isEnabledCredentialProviderService with componentName: "
+ componentName.flattenToString());
// TODO(253157366): Check additional set of services.
@@ -829,7 +828,7 @@ public final class CredentialManagerService
IClearCredentialStateCallback callback,
String callingPackage) {
final long timestampBegan = System.nanoTime();
- Slog.d(TAG, "starting clearCredentialState with callingPackage: "
+ Slog.i(TAG, "starting clearCredentialState with callingPackage: "
+ callingPackage);
final int userId = UserHandle.getCallingUserId();
int callingUid = Binder.getCallingUid();
@@ -882,7 +881,7 @@ public final class CredentialManagerService
public void registerCredentialDescription(
RegisterCredentialDescriptionRequest request, String callingPackage)
throws IllegalArgumentException, NonCredentialProviderCallerException {
- Slog.d(TAG, "registerCredentialDescription with callingPackage: " + callingPackage);
+ Slog.i(TAG, "registerCredentialDescription with callingPackage: " + callingPackage);
if (!isCredentialDescriptionApiEnabled()) {
throw new UnsupportedOperationException();
@@ -900,7 +899,7 @@ public final class CredentialManagerService
public void unregisterCredentialDescription(
UnregisterCredentialDescriptionRequest request, String callingPackage)
throws IllegalArgumentException {
- Slog.d(TAG, "unregisterCredentialDescription with callingPackage: "
+ Slog.i(TAG, "unregisterCredentialDescription with callingPackage: "
+ callingPackage);
@@ -962,7 +961,6 @@ public final class CredentialManagerService
@Override
@GuardedBy("mLock")
public void onFinishRequestSession(@UserIdInt int userId, IBinder token) {
- Log.i(TAG, "In onFinishRequestSession");
if (mRequestSessions.get(userId) != null) {
mRequestSessions.get(userId).remove(token);
}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
index 91be2a734e85..808fdaea3de6 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
@@ -48,7 +48,7 @@ public final class CredentialManagerServiceImpl extends
@NonNull Object lock, int userId, String serviceName)
throws PackageManager.NameNotFoundException {
super(master, lock, userId);
- Slog.d(TAG, "CredentialManagerServiceImpl constructed for: " + serviceName);
+ Slog.i(TAG, "CredentialManagerServiceImpl constructed for: " + serviceName);
synchronized (mLock) {
newServiceInfoLocked(ComponentName.unflattenFromString(serviceName));
}
@@ -63,7 +63,7 @@ public final class CredentialManagerServiceImpl extends
@NonNull CredentialManagerService master,
@NonNull Object lock, int userId, CredentialProviderInfo providerInfo) {
super(master, lock, userId);
- Slog.d(TAG, "CredentialManagerServiceImpl constructed for: "
+ Slog.i(TAG, "CredentialManagerServiceImpl constructed for: "
+ providerInfo.getServiceInfo().getComponentName().flattenToString());
mInfo = providerInfo;
}
@@ -74,11 +74,11 @@ public final class CredentialManagerServiceImpl extends
throws PackageManager.NameNotFoundException {
// TODO : Test update flows with multiple providers
if (mInfo != null) {
- Slog.d(TAG, "newServiceInfoLocked, mInfo not null : "
+ Slog.i(TAG, "newServiceInfoLocked, mInfo not null : "
+ mInfo.getServiceInfo().getComponentName().flattenToString() + " , "
+ serviceComponent.flattenToString());
} else {
- Slog.d(TAG, "newServiceInfoLocked, mInfo null, "
+ Slog.i(TAG, "newServiceInfoLocked, mInfo null, "
+ serviceComponent.flattenToString());
}
mInfo = CredentialProviderInfoFactory.create(
@@ -95,11 +95,11 @@ public final class CredentialManagerServiceImpl extends
public ProviderSession initiateProviderSessionForRequestLocked(
RequestSession requestSession, List<String> requestOptions) {
if (!requestOptions.isEmpty() && !isServiceCapableLocked(requestOptions)) {
- Slog.d(TAG, "Service does not have the required capabilities");
+ Slog.i(TAG, "Service does not have the required capabilities");
return null;
}
if (mInfo == null) {
- Slog.w(TAG, "in initiateProviderSessionForRequest in CredManServiceImpl, "
+ Slog.w(TAG, "Initiating provider session for request "
+ "but mInfo is null. This shouldn't happen");
return null;
}
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index 0271727249b1..15034104b5e0 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -72,7 +72,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
.createNewSession(mContext, mUserId, providerInfo,
this, remoteCredentialService);
if (providerGetSession != null) {
- Slog.d(TAG, "In startProviderSession - provider session created and "
+ Slog.i(TAG, "Provider session created and "
+ "being added for: " + providerInfo.getComponentName());
mProviders.put(providerGetSession.getComponentName().flattenToString(),
providerGetSession);
@@ -114,7 +114,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
@Override
public void onFinalResponseReceived(ComponentName componentName,
@Nullable GetCredentialResponse response) {
- Slog.d(TAG, "onFinalResponseReceived from: " + componentName.flattenToString());
+ Slog.i(TAG, "onFinalResponseReceived from: " + componentName.flattenToString());
mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime());
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(
mProviders.get(componentName.flattenToString())
@@ -158,7 +158,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
@Override
public void onProviderStatusChanged(ProviderSession.Status status,
ComponentName componentName, ProviderSession.CredentialsSource source) {
- Slog.d(TAG, "in onStatusChanged for: " + componentName + ", with status: "
+ Slog.i(TAG, "Status changed for: " + componentName + ", with status: "
+ status + ", and source: " + source);
// Auth entry was selected, and it did not have any underlying credentials
@@ -172,7 +172,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
// or we need to respond with error. The only other case is the entry being
// selected after the UI has been invoked which has a separate code path.
if (isUiInvocationNeeded()) {
- Slog.d(TAG, "in onProviderStatusChanged - isUiInvocationNeeded");
+ Slog.i(TAG, "Provider status changed - ui invocation is needed");
getProviderDataAndInitiateUi();
} else {
respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL,
diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
index 4e82ee71ac1b..47502c24fbd7 100644
--- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java
+++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
@@ -19,7 +19,7 @@ package com.android.server.credentials;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.util.Log;
+import android.util.Slog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.credentials.metrics.ApiName;
@@ -27,6 +27,7 @@ import com.android.server.credentials.metrics.ApiStatus;
import com.android.server.credentials.metrics.CandidateBrowsingPhaseMetric;
import com.android.server.credentials.metrics.CandidatePhaseMetric;
import com.android.server.credentials.metrics.ChosenProviderFinalPhaseMetric;
+import com.android.server.credentials.metrics.EntryEnum;
import com.android.server.credentials.metrics.InitialPhaseMetric;
import java.util.List;
@@ -69,7 +70,7 @@ public class MetricUtilities {
componentName.getPackageName(),
PackageManager.ApplicationInfoFlags.of(0)).uid;
} catch (Throwable t) {
- Log.i(TAG, "Couldn't find required uid");
+ Slog.i(TAG, "Couldn't find required uid");
}
return sessUid;
}
@@ -147,28 +148,28 @@ public class MetricUtilities {
.getFinalFinishTimeNanoseconds()),
/* chosen_provider_status */ finalPhaseMetric.getChosenProviderStatus(),
/* chosen_provider_has_exception */ finalPhaseMetric.isHasException(),
- /* chosen_provider_available_entries */ finalPhaseMetric.getAvailableEntries()
- .stream().mapToInt(i -> i).toArray(),
- /* chosen_provider_action_entry_count */ finalPhaseMetric.getActionEntryCount(),
- /* chosen_provider_credential_entry_count */
- finalPhaseMetric.getCredentialEntryCount(),
- /* chosen_provider_credential_entry_type_count */
- finalPhaseMetric.getCredentialEntryTypeCount(),
- /* chosen_provider_remote_entry_count */
- finalPhaseMetric.getRemoteEntryCount(),
- /* chosen_provider_authentication_entry_count */
- finalPhaseMetric.getAuthenticationEntryCount(),
+ /* chosen_provider_available_entries (deprecated) */ DEFAULT_REPEATED_INT_32,
+ /* chosen_provider_action_entry_count (deprecated) */ DEFAULT_INT_32,
+ /* chosen_provider_credential_entry_count (deprecated)*/DEFAULT_INT_32,
+ /* chosen_provider_credential_entry_type_count (deprecated) */ DEFAULT_INT_32,
+ /* chosen_provider_remote_entry_count (deprecated) */ DEFAULT_INT_32,
+ /* chosen_provider_authentication_entry_count (deprecated) */ DEFAULT_INT_32,
/* clicked_entries */ browsedClickedEntries,
/* provider_of_clicked_entry */ browsedProviderUid,
/* api_status */ apiStatus,
- DEFAULT_REPEATED_INT_32,
- DEFAULT_REPEATED_INT_32,
- DEFAULT_REPEATED_STR,
- DEFAULT_REPEATED_INT_32,
+ /* unique_entries */
+ finalPhaseMetric.getResponseCollective().getUniqueEntries(),
+ /* per_entry_counts */
+ finalPhaseMetric.getResponseCollective().getUniqueEntryCounts(),
+ /* unique_response_classtypes */
+ finalPhaseMetric.getResponseCollective().getUniqueResponseStrings(),
+ /* per_classtype_counts */
+ finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(),
+ /* framework_exception_unique_classtypes */
DEFAULT_STRING
);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.w(TAG, "Unexpected error during final provider uid emit: " + e);
}
}
@@ -223,12 +224,18 @@ public class MetricUtilities {
metric.getQueryFinishTimeNanoseconds());
candidateStatusList[index] = metric.getProviderQueryStatus();
candidateHasExceptionList[index] = metric.isHasException();
- candidateTotalEntryCountList[index] = metric.getNumEntriesTotal();
- candidateCredentialEntryCountList[index] = metric.getCredentialEntryCount();
- candidateCredentialTypeCountList[index] = metric.getCredentialEntryTypeCount();
- candidateActionEntryCountList[index] = metric.getActionEntryCount();
- candidateAuthEntryCountList[index] = metric.getAuthenticationEntryCount();
- candidateRemoteEntryCountList[index] = metric.getRemoteEntryCount();
+ candidateTotalEntryCountList[index] = metric.getResponseCollective()
+ .getNumEntriesTotal();
+ candidateCredentialEntryCountList[index] = metric.getResponseCollective()
+ .getCountForEntry(EntryEnum.CREDENTIAL_ENTRY);
+ candidateCredentialTypeCountList[index] = metric.getResponseCollective()
+ .getUniqueResponseStrings().length;
+ candidateActionEntryCountList[index] = metric.getResponseCollective()
+ .getCountForEntry(EntryEnum.ACTION_ENTRY);
+ candidateAuthEntryCountList[index] = metric.getResponseCollective()
+ .getCountForEntry(EntryEnum.AUTHENTICATION_ENTRY);
+ candidateRemoteEntryCountList[index] = metric.getResponseCollective()
+ .getCountForEntry(EntryEnum.REMOTE_ENTRY);
frameworkExceptionList[index] = metric.getFrameworkException();
index++;
}
@@ -262,7 +269,7 @@ public class MetricUtilities {
initialPhaseMetric.getUniqueRequestCounts()
);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.w(TAG, "Unexpected error during candidate provider uid metric emit: " + e);
}
}
@@ -298,7 +305,7 @@ public class MetricUtilities {
DEFAULT_INT_32,
/* chosen_provider_status */ DEFAULT_INT_32);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.w(TAG, "Unexpected error during metric logging: " + e);
}
}
@@ -331,7 +338,7 @@ public class MetricUtilities {
initialPhaseMetric.isOriginSpecified()
);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.w(TAG, "Unexpected error during initial metric emit: " + e);
}
}
}
diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
index 441c87b1569a..36bc8baa05dd 100644
--- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
@@ -66,7 +66,7 @@ public class PrepareGetRequestSession extends GetRequestSession {
@Override
public void onProviderStatusChanged(ProviderSession.Status status, ComponentName componentName,
ProviderSession.CredentialsSource source) {
- Slog.d(TAG, "in onProviderStatusChanged with status: " + status + ", and "
+ Slog.i(TAG, "Provider Status changed with status: " + status + ", and "
+ "source: " + source);
switch (source) {
diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
index 8af6b56f881d..c1fb92d30fc3 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
@@ -80,7 +80,7 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS
@Override
public void onProviderResponseSuccess(@Nullable Void response) {
- Slog.d(TAG, "Remote provider responded with a valid response: " + mComponentName);
+ Slog.i(TAG, "Remote provider responded with a valid response: " + mComponentName);
mProviderResponseSet = true;
updateStatusAndInvokeCallback(Status.COMPLETE,
/*source=*/ CredentialsSource.REMOTE_PROVIDER);
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 520b937d24c5..4cdc6f445212 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -75,7 +75,8 @@ public final class ProviderCreateSession extends ProviderSession<
CreateCredentialRequest providerCreateRequest =
createProviderRequest(providerInfo.getCapabilities(),
createRequestSession.mClientRequest,
- createRequestSession.mClientAppInfo);
+ createRequestSession.mClientAppInfo,
+ providerInfo.isSystemProvider());
if (providerCreateRequest != null) {
return new ProviderCreateSession(
context,
@@ -92,7 +93,7 @@ public final class ProviderCreateSession extends ProviderSession<
createRequestSession.mHybridService
);
}
- Slog.d(TAG, "Unable to create provider session for: "
+ Slog.i(TAG, "Unable to create provider session for: "
+ providerInfo.getComponentName());
return null;
}
@@ -114,9 +115,16 @@ public final class ProviderCreateSession extends ProviderSession<
}
@Nullable
- private static CreateCredentialRequest createProviderRequest(List<String> providerCapabilities,
+ private static CreateCredentialRequest createProviderRequest(
+ List<String> providerCapabilities,
android.credentials.CreateCredentialRequest clientRequest,
- CallingAppInfo callingAppInfo) {
+ CallingAppInfo callingAppInfo,
+ boolean isSystemProvider) {
+ if (clientRequest.isSystemProviderRequired() && !isSystemProvider) {
+ // Request requires system provider but this session does not correspond to a
+ // system service
+ return null;
+ }
String capability = clientRequest.getType();
if (providerCapabilities.contains(capability)) {
return new CreateCredentialRequest(callingAppInfo, capability,
@@ -145,7 +153,7 @@ public final class ProviderCreateSession extends ProviderSession<
@Override
public void onProviderResponseSuccess(
@Nullable BeginCreateCredentialResponse response) {
- Slog.d(TAG, "Remote provider responded with a valid response: " + mComponentName);
+ Slog.i(TAG, "Remote provider responded with a valid response: " + mComponentName);
onSetInitialRemoteResponse(response);
}
@@ -200,7 +208,7 @@ public final class ProviderCreateSession extends ProviderSession<
protected CreateCredentialProviderData prepareUiData()
throws IllegalArgumentException {
if (!ProviderSession.isUiInvokingStatus(getStatus())) {
- Slog.d(TAG, "No data for UI from: " + mComponentName.flattenToString());
+ Slog.i(TAG, "No data for UI from: " + mComponentName.flattenToString());
return null;
}
@@ -216,7 +224,7 @@ public final class ProviderCreateSession extends ProviderSession<
switch (entryType) {
case SAVE_ENTRY_KEY:
if (mProviderResponseDataHandler.getCreateEntry(entryKey) == null) {
- Slog.w(TAG, "Unexpected save entry key");
+ Slog.i(TAG, "Unexpected save entry key");
invokeCallbackOnInternalInvalidState();
return;
}
@@ -224,14 +232,14 @@ public final class ProviderCreateSession extends ProviderSession<
break;
case REMOTE_ENTRY_KEY:
if (mProviderResponseDataHandler.getRemoteEntry(entryKey) == null) {
- Slog.w(TAG, "Unexpected remote entry key");
+ Slog.i(TAG, "Unexpected remote entry key");
invokeCallbackOnInternalInvalidState();
return;
}
onRemoteEntrySelected(providerPendingIntentResponse);
break;
default:
- Slog.w(TAG, "Unsupported entry type selected");
+ Slog.i(TAG, "Unsupported entry type selected");
invokeCallbackOnInternalInvalidState();
}
}
@@ -266,7 +274,7 @@ public final class ProviderCreateSession extends ProviderSession<
if (credentialResponse != null) {
mCallbacks.onFinalResponseReceived(mComponentName, credentialResponse);
} else {
- Slog.w(TAG, "onSaveEntrySelected - no response or error found in pending "
+ Slog.i(TAG, "onSaveEntrySelected - no response or error found in pending "
+ "intent response");
invokeCallbackOnInternalInvalidState();
}
@@ -282,14 +290,14 @@ public final class ProviderCreateSession extends ProviderSession<
private CreateCredentialException maybeGetPendingIntentException(
ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
- Slog.w(TAG, "pendingIntentResponse is null");
+ Slog.i(TAG, "pendingIntentResponse is null");
return new CreateCredentialException(CreateCredentialException.TYPE_NO_CREATE_OPTIONS);
}
if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
CreateCredentialException exception = PendingIntentResultHandler
.extractCreateCredentialException(pendingIntentResponse.getResultData());
if (exception != null) {
- Slog.d(TAG, "Pending intent contains provider exception");
+ Slog.i(TAG, "Pending intent contains provider exception");
return exception;
}
} else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 0c3d2a4c000a..8070fa7ca9aa 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -114,7 +114,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
getRequestSession.mHybridService
);
}
- Slog.d(TAG, "Unable to create provider session for: "
+ Slog.i(TAG, "Unable to create provider session for: "
+ providerInfo.getComponentName());
return null;
}
@@ -146,13 +146,13 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
android.credentials.GetCredentialRequest clientRequest,
CredentialProviderInfo info
) {
- Slog.d(TAG, "Filtering request options for: " + info.getComponentName());
+ Slog.i(TAG, "Filtering request options for: " + info.getComponentName());
List<CredentialOption> filteredOptions = new ArrayList<>();
for (CredentialOption option : clientRequest.getCredentialOptions()) {
if (providerCapabilities.contains(option.getType())
&& isProviderAllowed(option, info.getComponentName())
&& checkSystemProviderRequirement(option, info.isSystemProvider())) {
- Slog.d(TAG, "Option of type: " + option.getType() + " meets all filtering"
+ Slog.i(TAG, "Option of type: " + option.getType() + " meets all filtering"
+ "conditions");
filteredOptions.add(option);
}
@@ -163,14 +163,14 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
.setCredentialOptions(
filteredOptions).build();
}
- Slog.d(TAG, "No options filtered");
+ Slog.i(TAG, "No options filtered");
return null;
}
private static boolean isProviderAllowed(CredentialOption option, ComponentName componentName) {
if (!option.getAllowedProviders().isEmpty() && !option.getAllowedProviders().contains(
componentName)) {
- Slog.d(TAG, "Provider allow list specified but does not contain this provider");
+ Slog.i(TAG, "Provider allow list specified but does not contain this provider");
return false;
}
return true;
@@ -179,7 +179,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
private static boolean checkSystemProviderRequirement(CredentialOption option,
boolean isSystemProvider) {
if (option.isSystemProviderRequired() && !isSystemProvider) {
- Slog.d(TAG, "System provider required, but this service is not a system provider");
+ Slog.i(TAG, "System provider required, but this service is not a system provider");
return false;
}
return true;
@@ -207,7 +207,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
/** Called when the provider response has been updated by an external source. */
@Override // Callback from the remote provider
public void onProviderResponseSuccess(@Nullable BeginGetCredentialResponse response) {
- Slog.d(TAG, "Remote provider responded with a valid response: " + mComponentName);
+ Slog.i(TAG, "Remote provider responded with a valid response: " + mComponentName);
onSetInitialRemoteResponse(response);
}
@@ -244,14 +244,14 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
@Override // Selection call from the request provider
protected void onUiEntrySelected(String entryType, String entryKey,
ProviderPendingIntentResponse providerPendingIntentResponse) {
- Slog.d(TAG, "onUiEntrySelected with entryType: " + entryType + ", and entryKey: "
+ Slog.i(TAG, "onUiEntrySelected with entryType: " + entryType + ", and entryKey: "
+ entryKey);
switch (entryType) {
case CREDENTIAL_ENTRY_KEY:
CredentialEntry credentialEntry = mProviderResponseDataHandler
.getCredentialEntry(entryKey);
if (credentialEntry == null) {
- Slog.w(TAG, "Unexpected credential entry key");
+ Slog.i(TAG, "Unexpected credential entry key");
invokeCallbackOnInternalInvalidState();
return;
}
@@ -260,7 +260,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
case ACTION_ENTRY_KEY:
Action actionEntry = mProviderResponseDataHandler.getActionEntry(entryKey);
if (actionEntry == null) {
- Slog.w(TAG, "Unexpected action entry key");
+ Slog.i(TAG, "Unexpected action entry key");
invokeCallbackOnInternalInvalidState();
return;
}
@@ -270,21 +270,21 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
Action authenticationEntry = mProviderResponseDataHandler
.getAuthenticationAction(entryKey);
if (authenticationEntry == null) {
- Slog.w(TAG, "Unexpected authenticationEntry key");
+ Slog.i(TAG, "Unexpected authenticationEntry key");
invokeCallbackOnInternalInvalidState();
return;
}
boolean additionalContentReceived =
onAuthenticationEntrySelected(providerPendingIntentResponse);
if (additionalContentReceived) {
- Slog.d(TAG, "Additional content received - removing authentication entry");
+ Slog.i(TAG, "Additional content received - removing authentication entry");
mProviderResponseDataHandler.removeAuthenticationAction(entryKey);
if (!mProviderResponseDataHandler.isEmptyResponse()) {
updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED,
/*source=*/ CredentialsSource.AUTH_ENTRY);
}
} else {
- Slog.d(TAG, "Additional content not received from authentication entry");
+ Slog.i(TAG, "Additional content not received from authentication entry");
mProviderResponseDataHandler
.updateAuthEntryWithNoCredentialsReceived(entryKey);
updateStatusAndInvokeCallback(Status.NO_CREDENTIALS_FROM_AUTH_ENTRY,
@@ -295,12 +295,12 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
if (mProviderResponseDataHandler.getRemoteEntry(entryKey) != null) {
onRemoteEntrySelected(providerPendingIntentResponse);
} else {
- Slog.d(TAG, "Unexpected remote entry key");
+ Slog.i(TAG, "Unexpected remote entry key");
invokeCallbackOnInternalInvalidState();
}
break;
default:
- Slog.w(TAG, "Unsupported entry type selected");
+ Slog.i(TAG, "Unsupported entry type selected");
invokeCallbackOnInternalInvalidState();
}
}
@@ -322,13 +322,12 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
@Nullable
protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException {
if (!ProviderSession.isUiInvokingStatus(getStatus())) {
- Slog.d(TAG, "No data for UI from: " + mComponentName.flattenToString());
+ Slog.i(TAG, "No data for UI from: " + mComponentName.flattenToString());
return null;
}
if (mProviderResponse != null && !mProviderResponseDataHandler.isEmptyResponse()) {
return mProviderResponseDataHandler.toGetCredentialProviderData();
}
- Slog.d(TAG, "In prepareUiData response null");
return null;
}
@@ -381,7 +380,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
getCredentialResponse);
return;
}
- Slog.d(TAG, "Pending intent response contains no credential, or error "
+ Slog.i(TAG, "Pending intent response contains no credential, or error "
+ "for a credential entry");
invokeCallbackOnInternalInvalidState();
}
@@ -459,7 +458,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
/** Returns true if either an exception or a response is found. */
private void onActionEntrySelected(ProviderPendingIntentResponse
providerPendingIntentResponse) {
- Slog.d(TAG, "onActionEntrySelected");
+ Slog.i(TAG, "onActionEntrySelected");
onCredentialEntrySelected(providerPendingIntentResponse);
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
index ead86cefc5d4..b0b72bcf67cc 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
@@ -171,11 +171,11 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption
@Override
protected ProviderData prepareUiData() {
if (!ProviderSession.isUiInvokingStatus(getStatus())) {
- Slog.d(TAG, "No date for UI coming from: " + mComponentName.flattenToString());
+ Slog.i(TAG, "No date for UI coming from: " + mComponentName.flattenToString());
return null;
}
if (mProviderResponse == null) {
- Slog.w(TAG, "In prepareUiData but response is null. This is strange.");
+ Slog.w(TAG, "response is null when preparing ui data. This is strange.");
return null;
}
return new GetCredentialProviderData.Builder(
@@ -196,13 +196,13 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption
case CREDENTIAL_ENTRY_KEY:
CredentialEntry credentialEntry = mUiCredentialEntries.get(entryKey);
if (credentialEntry == null) {
- Slog.w(TAG, "Unexpected credential entry key");
+ Slog.i(TAG, "Unexpected credential entry key");
return;
}
onCredentialEntrySelected(credentialEntry, providerPendingIntentResponse);
break;
default:
- Slog.w(TAG, "Unsupported entry type selected");
+ Slog.i(TAG, "Unsupported entry type selected");
}
}
@@ -256,6 +256,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption
@Override
protected void invokeSession() {
+ startCandidateMetrics();
mProviderResponse = mCredentialDescriptionRegistry
.getFilteredResultForProvider(mCredentialProviderPackageName,
mElementKeys);
@@ -266,7 +267,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption
.collect(Collectors.toList());
updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED,
/*source=*/ CredentialsSource.REGISTRY);
- // TODO(b/273353677) : metric should be emitted similarly to sibling classes
+ mProviderSessionMetric.collectCandidateEntryMetrics(mCredentialEntries);
}
@Nullable
@@ -279,7 +280,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption
GetCredentialException exception = PendingIntentResultHandler
.extractGetCredentialException(pendingIntentResponse.getResultData());
if (exception != null) {
- Slog.d(TAG, "Pending intent contains provider exception");
+ Slog.i(TAG, "Pending intent contains provider exception");
return exception;
}
} else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
index 0ad73c945284..f5e3b86213a1 100644
--- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
+++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
@@ -292,13 +292,13 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
callback.onProviderResponseSuccess(result);
} else {
if (error instanceof TimeoutException) {
- Slog.d(TAG, "Remote provider response timed tuo for: " + mComponentName);
+ Slog.i(TAG, "Remote provider response timed tuo for: " + mComponentName);
dispatchCancellationSignal(cancellationSink.get());
callback.onProviderResponseFailure(
CredentialProviderErrors.ERROR_TIMEOUT,
null);
} else if (error instanceof CancellationException) {
- Slog.d(TAG, "Cancellation exception for remote provider: " + mComponentName);
+ Slog.i(TAG, "Cancellation exception for remote provider: " + mComponentName);
dispatchCancellationSignal(cancellationSink.get());
callback.onProviderResponseFailure(
CredentialProviderErrors.ERROR_TASK_CANCELED,
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index 15a30e427688..7caa921eacda 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -201,7 +201,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
}
protected void finishSession(boolean propagateCancellation) {
- Slog.d(TAG, "finishing session with propagateCancellation " + propagateCancellation);
+ Slog.i(TAG, "finishing session with propagateCancellation " + propagateCancellation);
if (propagateCancellation) {
mProviders.values().forEach(ProviderSession::cancelProviderRemoteSession);
}
@@ -265,7 +265,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
@NonNull
protected ArrayList<ProviderData> getProviderDataForUi() {
- Slog.d(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size());
+ Slog.i(TAG, "For ui, provider data size: " + mProviders.size());
ArrayList<ProviderData> providerDataList = new ArrayList<>();
mRequestSessionMetric.logCandidatePhaseMetrics(mProviders);
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
index b99f28d07f75..1930a4859e87 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
@@ -27,7 +27,7 @@ import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INI
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNKNOWN;
import android.credentials.ui.RequestInfo;
-import android.util.Log;
+import android.util.Slog;
import java.util.AbstractMap;
import java.util.Map;
@@ -79,7 +79,7 @@ CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_IS_ENABLED_CREDENT
*/
public static int getMetricCodeFromRequestInfo(String stringKey) {
if (!sRequestInfoToMetric.containsKey(stringKey)) {
- Log.w(TAG, "Attempted to use an unsupported string key request info");
+ Slog.i(TAG, "Attempted to use an unsupported string key request info");
return UNKNOWN.mInnerMetricCode;
}
return sRequestInfoToMetric.get(stringKey);
diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java
index 0e1e03897bf1..07af6549411e 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java
@@ -27,8 +27,6 @@ package com.android.server.credentials.metrics;
* though collection will begin in the candidate phase when the user begins browsing options.
*/
public class CandidateBrowsingPhaseMetric {
-
- private static final String TAG = "CandidateBrowsingPhaseMetric";
// The session id associated with the API Call this candidate provider is a part of, default -1
private int mSessionId = -1;
// The EntryEnum that was pressed, defaults to -1
diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
index b212606b8271..3ea9b1ce86f8 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
@@ -16,14 +16,12 @@
package com.android.server.credentials.metrics;
-import android.util.IntArray;
-import android.util.Log;
+import android.util.Slog;
import com.android.server.credentials.MetricUtilities;
+import com.android.server.credentials.metrics.shared.ResponseCollective;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
+import java.util.Map;
/**
* The central candidate provider metric object that mimics our defined metric setup.
@@ -55,23 +53,12 @@ public class CandidatePhaseMetric {
private int mProviderQueryStatus = -1;
// Indicates if an exception was thrown by this provider, false by default
private boolean mHasException = false;
- // Indicates the number of total entries available, defaults to -1
- private int mNumEntriesTotal = -1;
- // The count of action entries from this provider, defaults to -1
- private int mActionEntryCount = -1;
- // The count of credential entries from this provider, defaults to -1
- private int mCredentialEntryCount = -1;
- // The *type-count* of the credential entries, defaults to -1
- private int mCredentialEntryTypeCount = -1;
- // The count of remote entries from this provider, defaults to -1
- private int mRemoteEntryCount = -1;
- // The count of authentication entries from this provider, defaults to -1
- private int mAuthenticationEntryCount = -1;
- // Gathered to pass on to chosen provider when required
- private final IntArray mAvailableEntries = new IntArray();
- // The *framework only* exception held by this provider, empty string by default
private String mFrameworkException = "";
+ // Stores the response credential information, as well as the response entry information which
+ // by default, contains empty info
+ private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of());
+
public CandidatePhaseMetric() {
}
@@ -125,7 +112,7 @@ public class CandidatePhaseMetric {
*/
public int getTimestampFromReferenceStartMicroseconds(long specificTimestamp) {
if (specificTimestamp < mServiceBeganTimeNanoseconds) {
- Log.i(TAG, "The timestamp is before service started, falling back to default int");
+ Slog.i(TAG, "The timestamp is before service started, falling back to default int");
return MetricUtilities.DEFAULT_INT_32;
}
return (int) ((specificTimestamp
@@ -182,88 +169,13 @@ public class CandidatePhaseMetric {
return mHasException;
}
- /* -------------- Number of Entries ---------------- */
-
- public void setNumEntriesTotal(int numEntriesTotal) {
- mNumEntriesTotal = numEntriesTotal;
- }
-
- public int getNumEntriesTotal() {
- return mNumEntriesTotal;
- }
-
- /* -------------- Count of Action Entries ---------------- */
-
- public void setActionEntryCount(int actionEntryCount) {
- mActionEntryCount = actionEntryCount;
- }
-
- public int getActionEntryCount() {
- return mActionEntryCount;
- }
-
- /* -------------- Count of Credential Entries ---------------- */
-
- public void setCredentialEntryCount(int credentialEntryCount) {
- mCredentialEntryCount = credentialEntryCount;
- }
-
- public int getCredentialEntryCount() {
- return mCredentialEntryCount;
- }
-
- /* -------------- Count of Credential Entry Types ---------------- */
-
- public void setCredentialEntryTypeCount(int credentialEntryTypeCount) {
- mCredentialEntryTypeCount = credentialEntryTypeCount;
- }
-
- public int getCredentialEntryTypeCount() {
- return mCredentialEntryTypeCount;
+ /* -------------- The Entries and Responses Gathered ---------------- */
+ public void setResponseCollective(ResponseCollective responseCollective) {
+ mResponseCollective = responseCollective;
}
- /* -------------- Count of Remote Entries ---------------- */
-
- public void setRemoteEntryCount(int remoteEntryCount) {
- mRemoteEntryCount = remoteEntryCount;
- }
-
- public int getRemoteEntryCount() {
- return mRemoteEntryCount;
- }
-
- /* -------------- Count of Authentication Entries ---------------- */
-
- public void setAuthenticationEntryCount(int authenticationEntryCount) {
- mAuthenticationEntryCount = authenticationEntryCount;
- }
-
- public int getAuthenticationEntryCount() {
- return mAuthenticationEntryCount;
- }
-
- /* -------------- The Entries Gathered ---------------- */
-
- /**
- * Allows adding an entry record to this metric collector, which can then be propagated to
- * the final phase to retain information on the data available to the candidate.
- *
- * @param e the entry enum collected by the candidate provider associated with this metric
- * collector
- */
- public void addEntry(EntryEnum e) {
- mAvailableEntries.add(e.getMetricCode());
- }
-
- /**
- * Returns a safely copied list of the entries captured by this metric collector associated
- * with a particular candidate provider.
- *
- * @return the full collection of entries encountered by the candidate provider associated with
- * this metric
- */
- public List<Integer> getAvailableEntries() {
- return Arrays.stream(mAvailableEntries.toArray()).boxed().collect(Collectors.toList());
+ public ResponseCollective getResponseCollective() {
+ return mResponseCollective;
}
/* ------ Framework Exception for this Candidate ------ */
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
index 8f08bb02dfd0..93a82906aa50 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
@@ -16,12 +16,12 @@
package com.android.server.credentials.metrics;
-import android.util.Log;
+import android.util.Slog;
import com.android.server.credentials.MetricUtilities;
+import com.android.server.credentials.metrics.shared.ResponseCollective;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Map;
/**
* The central chosen provider metric object that mimics our defined metric setup. This is used
@@ -66,21 +66,10 @@ public class ChosenProviderFinalPhaseMetric {
private int mChosenProviderStatus = -1;
// Indicates if an exception was thrown by this provider, false by default
private boolean mHasException = false;
- // Indicates the number of total entries available, defaults to -1. Not presently emitted, but
- // left as a utility
- private int mNumEntriesTotal = -1;
- // The count of action entries from this provider, defaults to -1
- private int mActionEntryCount = -1;
- // The count of credential entries from this provider, defaults to -1
- private int mCredentialEntryCount = -1;
- // The *type-count* of the credential entries, defaults to -1
- private int mCredentialEntryTypeCount = -1;
- // The count of remote entries from this provider, defaults to -1
- private int mRemoteEntryCount = -1;
- // The count of authentication entries from this provider, defaults to -1
- private int mAuthenticationEntryCount = -1;
- // Gathered to pass on to chosen provider when required
- private List<Integer> mAvailableEntries = new ArrayList<>();
+
+ // Stores the response credential information, as well as the response entry information which
+ // by default, contains empty info
+ private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of());
public ChosenProviderFinalPhaseMetric() {
@@ -227,7 +216,7 @@ public class ChosenProviderFinalPhaseMetric {
*/
public int getTimestampFromReferenceStartMicroseconds(long specificTimestamp) {
if (specificTimestamp < mServiceBeganTimeNanoseconds) {
- Log.i(TAG, "The timestamp is before service started, falling back to default int");
+ Slog.i(TAG, "The timestamp is before service started, falling back to default int");
return MetricUtilities.DEFAULT_INT_32;
}
return (int) ((specificTimestamp
@@ -264,87 +253,6 @@ public class ChosenProviderFinalPhaseMetric {
return mUiReturned;
}
- /* -------------- Number of Entries ---------------- */
-
- public void setNumEntriesTotal(int numEntriesTotal) {
- mNumEntriesTotal = numEntriesTotal;
- }
-
- public int getNumEntriesTotal() {
- return mNumEntriesTotal;
- }
-
- /* -------------- Count of Action Entries ---------------- */
-
- public void setActionEntryCount(int actionEntryCount) {
- mActionEntryCount = actionEntryCount;
- }
-
- public int getActionEntryCount() {
- return mActionEntryCount;
- }
-
- /* -------------- Count of Credential Entries ---------------- */
-
- public void setCredentialEntryCount(int credentialEntryCount) {
- mCredentialEntryCount = credentialEntryCount;
- }
-
- public int getCredentialEntryCount() {
- return mCredentialEntryCount;
- }
-
- /* -------------- Count of Credential Entry Types ---------------- */
-
- public void setCredentialEntryTypeCount(int credentialEntryTypeCount) {
- mCredentialEntryTypeCount = credentialEntryTypeCount;
- }
-
- public int getCredentialEntryTypeCount() {
- return mCredentialEntryTypeCount;
- }
-
- /* -------------- Count of Remote Entries ---------------- */
-
- public void setRemoteEntryCount(int remoteEntryCount) {
- mRemoteEntryCount = remoteEntryCount;
- }
-
- public int getRemoteEntryCount() {
- return mRemoteEntryCount;
- }
-
- /* -------------- Count of Authentication Entries ---------------- */
-
- public void setAuthenticationEntryCount(int authenticationEntryCount) {
- mAuthenticationEntryCount = authenticationEntryCount;
- }
-
- public int getAuthenticationEntryCount() {
- return mAuthenticationEntryCount;
- }
-
- /* -------------- The Entries Gathered ---------------- */
-
- /**
- * Sets the collected list of entries from the candidate phase to be retrievable in the
- * chosen phase in a semantically correct way.
- */
- public void setAvailableEntries(List<Integer> entries) {
- mAvailableEntries = new ArrayList<>(entries); // no alias copy
- }
-
- /**
- * Returns a list of the entries captured by this metric collector associated
- * with a particular chosen provider.
- *
- * @return the full collection of entries encountered by the chosen provider during the
- * candidate phase.
- */
- public List<Integer> getAvailableEntries() {
- return new ArrayList<>(mAvailableEntries); // no alias copy
- }
-
/* -------------- Has Exception ---------------- */
public void setHasException(boolean hasException) {
@@ -354,4 +262,14 @@ public class ChosenProviderFinalPhaseMetric {
public boolean isHasException() {
return mHasException;
}
+
+ /* -------------- The Entries and Responses Gathered ---------------- */
+
+ public void setResponseCollective(ResponseCollective responseCollective) {
+ mResponseCollective = responseCollective;
+ }
+
+ public ResponseCollective getResponseCollective() {
+ return mResponseCollective;
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/EntryEnum.java b/services/credentials/java/com/android/server/credentials/metrics/EntryEnum.java
index b9125ddf1145..530f01cbdfc5 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/EntryEnum.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/EntryEnum.java
@@ -26,7 +26,7 @@ import static com.android.server.credentials.ProviderGetSession.AUTHENTICATION_A
import static com.android.server.credentials.ProviderGetSession.CREDENTIAL_ENTRY_KEY;
import static com.android.server.credentials.ProviderGetSession.REMOTE_ENTRY_KEY;
-import android.util.Log;
+import android.util.Slog;
import java.util.AbstractMap;
import java.util.Map;
@@ -77,7 +77,7 @@ public enum EntryEnum {
*/
public static int getMetricCodeFromString(String stringKey) {
if (!sKeyToEntryCode.containsKey(stringKey)) {
- Log.w(TAG, "Attempted to use an unsupported string key entry type");
+ Slog.i(TAG, "Attempted to use an unsupported string key entry type");
return UNKNOWN.mInnerMetricCode;
}
return sKeyToEntryCode.get(stringKey);
diff --git a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
index 5cfb0e7d375b..060e56ce965b 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
@@ -16,8 +16,6 @@
package com.android.server.credentials.metrics;
-import android.util.Log;
-
import java.util.LinkedHashMap;
import java.util.Map;
@@ -48,7 +46,7 @@ public class InitialPhaseMetric {
// Indicates if the origin was specified when making this API request
private boolean mOriginSpecified = false;
- // Stores the deduped request information, particularly {"req":5}.
+ // Stores the deduped request information, particularly {"req":5}
private Map<String, Integer> mRequestCounts = new LinkedHashMap<>();
@@ -138,26 +136,20 @@ public class InitialPhaseMetric {
}
/**
- * Reruns the unique, deduped, request classtypes for logging.
+ * Returns the unique, deduped, request classtypes for logging.
* @return a string array for deduped classtypes
*/
public String[] getUniqueRequestStrings() {
- if (mRequestCounts.isEmpty()) {
- Log.w(TAG, "There are no unique string request types collected");
- }
String[] result = new String[mRequestCounts.keySet().size()];
mRequestCounts.keySet().toArray(result);
return result;
}
/**
- * Reruns the unique, deduped, request classtype counts for logging.
+ * Returns the unique, deduped, request classtype counts for logging.
* @return a string array for deduped classtype counts
*/
public int[] getUniqueRequestCounts() {
- if (mRequestCounts.isEmpty()) {
- Log.w(TAG, "There are no unique string request type counts collected");
- }
return mRequestCounts.values().stream().mapToInt(Integer::intValue).toArray();
}
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java
index 9a88255ce973..f011b554fe53 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java
@@ -16,15 +16,21 @@
package com.android.server.credentials.metrics;
+import static com.android.server.credentials.MetricUtilities.DELTA_CUT;
+import static com.android.server.credentials.MetricUtilities.generateMetricKey;
+
import android.annotation.NonNull;
import android.service.credentials.BeginCreateCredentialResponse;
import android.service.credentials.BeginGetCredentialResponse;
import android.service.credentials.CredentialEntry;
-import android.util.Log;
+import android.util.Slog;
import com.android.server.credentials.MetricUtilities;
+import com.android.server.credentials.metrics.shared.ResponseCollective;
-import java.util.stream.Collectors;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
/**
* Provides contextual metric collection for objects generated from
@@ -68,7 +74,7 @@ public class ProviderSessionMetric {
try {
mCandidatePhasePerProviderMetric.setFrameworkException(exceptionType);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error during candidate exception metric logging: " + e);
}
}
@@ -97,7 +103,7 @@ public class ProviderSessionMetric {
.getMetricCode());
}
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error during candidate update metric logging: " + e);
}
}
@@ -118,7 +124,7 @@ public class ProviderSessionMetric {
initMetric.getCredentialServiceStartedTimeNanoseconds());
mCandidatePhasePerProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime());
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error during candidate setup metric logging: " + e);
}
}
@@ -138,59 +144,79 @@ public class ProviderSessionMetric {
beginCreateCredentialResponseCollectionCandidateEntryMetrics(
(BeginCreateCredentialResponse) response);
} else {
- Log.i(TAG, "Your response type is unsupported for metric logging");
+ Slog.i(TAG, "Your response type is unsupported for metric logging");
}
-
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error during candidate entry metric logging: " + e);
}
}
+ /**
+ * Once entries are received from the registry, this helps collect their info for metric
+ * purposes.
+ *
+ * @param entries contains matching entries from the Credential Registry.
+ */
+ public void collectCandidateEntryMetrics(List<CredentialEntry> entries) {
+ int numCredEntries = entries.size();
+ int numRemoteEntry = MetricUtilities.ZERO;
+ int numActionEntries = MetricUtilities.ZERO;
+ int numAuthEntries = MetricUtilities.ZERO;
+ Map<EntryEnum, Integer> entryCounts = new LinkedHashMap<>();
+ Map<String, Integer> responseCounts = new LinkedHashMap<>();
+ entryCounts.put(EntryEnum.REMOTE_ENTRY, numRemoteEntry);
+ entryCounts.put(EntryEnum.CREDENTIAL_ENTRY, numCredEntries);
+ entryCounts.put(EntryEnum.ACTION_ENTRY, numActionEntries);
+ entryCounts.put(EntryEnum.AUTHENTICATION_ENTRY, numAuthEntries);
+
+ entries.forEach(entry -> {
+ String entryKey = generateMetricKey(entry.getType(), DELTA_CUT);
+ responseCounts.put(entryKey, responseCounts.getOrDefault(entryKey, 0) + 1);
+ });
+
+ ResponseCollective responseCollective = new ResponseCollective(responseCounts, entryCounts);
+ mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective);
+ }
+
private void beginCreateCredentialResponseCollectionCandidateEntryMetrics(
BeginCreateCredentialResponse response) {
+ Map<EntryEnum, Integer> entryCounts = new LinkedHashMap<>();
var createEntries = response.getCreateEntries();
- int numRemoteEntry = MetricUtilities.ZERO;
- if (response.getRemoteCreateEntry() != null) {
- numRemoteEntry = MetricUtilities.UNIT;
- mCandidatePhasePerProviderMetric.addEntry(EntryEnum.REMOTE_ENTRY);
- }
- int numCreateEntries =
- createEntries == null ? MetricUtilities.ZERO : createEntries.size();
- if (numCreateEntries > MetricUtilities.ZERO) {
- createEntries.forEach(c ->
- mCandidatePhasePerProviderMetric.addEntry(EntryEnum.CREDENTIAL_ENTRY));
- }
- mCandidatePhasePerProviderMetric.setNumEntriesTotal(numCreateEntries + numRemoteEntry);
- mCandidatePhasePerProviderMetric.setRemoteEntryCount(numRemoteEntry);
- mCandidatePhasePerProviderMetric.setCredentialEntryCount(numCreateEntries);
- mCandidatePhasePerProviderMetric.setCredentialEntryTypeCount(MetricUtilities.UNIT);
+ int numRemoteEntry = response.getRemoteCreateEntry() != null ? MetricUtilities.ZERO :
+ MetricUtilities.UNIT;
+ int numCreateEntries = createEntries.size();
+ entryCounts.put(EntryEnum.REMOTE_ENTRY, numRemoteEntry);
+ entryCounts.put(EntryEnum.CREDENTIAL_ENTRY, numCreateEntries);
+
+ Map<String, Integer> responseCounts = new LinkedHashMap<>();
+ responseCounts.put(MetricUtilities.DEFAULT_STRING, numCreateEntries);
+ // We don't store create response because it's directly related to the request
+ // We do still store the count, however
+
+ ResponseCollective responseCollective = new ResponseCollective(responseCounts, entryCounts);
+ mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective);
}
private void beginGetCredentialResponseCollectionCandidateEntryMetrics(
BeginGetCredentialResponse response) {
+ Map<EntryEnum, Integer> entryCounts = new LinkedHashMap<>();
+ Map<String, Integer> responseCounts = new LinkedHashMap<>();
int numCredEntries = response.getCredentialEntries().size();
int numActionEntries = response.getActions().size();
int numAuthEntries = response.getAuthenticationActions().size();
- int numRemoteEntry = MetricUtilities.ZERO;
- if (response.getRemoteCredentialEntry() != null) {
- numRemoteEntry = MetricUtilities.UNIT;
- mCandidatePhasePerProviderMetric.addEntry(EntryEnum.REMOTE_ENTRY);
- }
- response.getCredentialEntries().forEach(c ->
- mCandidatePhasePerProviderMetric.addEntry(EntryEnum.CREDENTIAL_ENTRY));
- response.getActions().forEach(c ->
- mCandidatePhasePerProviderMetric.addEntry(EntryEnum.ACTION_ENTRY));
- response.getAuthenticationActions().forEach(c ->
- mCandidatePhasePerProviderMetric.addEntry(EntryEnum.AUTHENTICATION_ENTRY));
- mCandidatePhasePerProviderMetric.setNumEntriesTotal(numCredEntries + numAuthEntries
- + numActionEntries + numRemoteEntry);
- mCandidatePhasePerProviderMetric.setCredentialEntryCount(numCredEntries);
- int numTypes = (response.getCredentialEntries().stream()
- .map(CredentialEntry::getType).collect(
- Collectors.toSet())).size(); // Dedupe type strings
- mCandidatePhasePerProviderMetric.setCredentialEntryTypeCount(numTypes);
- mCandidatePhasePerProviderMetric.setActionEntryCount(numActionEntries);
- mCandidatePhasePerProviderMetric.setAuthenticationEntryCount(numAuthEntries);
- mCandidatePhasePerProviderMetric.setRemoteEntryCount(numRemoteEntry);
+ int numRemoteEntry = response.getRemoteCredentialEntry() != null ? MetricUtilities.ZERO :
+ MetricUtilities.UNIT;
+ entryCounts.put(EntryEnum.REMOTE_ENTRY, numRemoteEntry);
+ entryCounts.put(EntryEnum.CREDENTIAL_ENTRY, numCredEntries);
+ entryCounts.put(EntryEnum.ACTION_ENTRY, numActionEntries);
+ entryCounts.put(EntryEnum.AUTHENTICATION_ENTRY, numAuthEntries);
+
+ response.getCredentialEntries().forEach(entry -> {
+ String entryKey = generateMetricKey(entry.getType(), DELTA_CUT);
+ responseCounts.put(entryKey, responseCounts.getOrDefault(entryKey, 0) + 1);
+ });
+
+ ResponseCollective responseCollective = new ResponseCollective(responseCounts, entryCounts);
+ mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
index 4ecdfef401b6..4624e0b3701a 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
@@ -24,7 +24,7 @@ import static com.android.server.credentials.MetricUtilities.logApiCalledFinalPh
import android.credentials.GetCredentialRequest;
import android.credentials.ui.UserSelectionDialogResult;
import android.os.IBinder;
-import android.util.Log;
+import android.util.Slog;
import com.android.server.credentials.ProviderSession;
@@ -90,7 +90,7 @@ public class RequestSessionMetric {
mInitialPhaseMetric.setCallerUid(mCallingUid);
mInitialPhaseMetric.setApiName(metricCode);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error collecting initial metrics: " + e);
}
}
@@ -103,7 +103,7 @@ public class RequestSessionMetric {
try {
mChosenProviderFinalPhaseMetric.setUiReturned(uiReturned);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error collecting ui end time metric: " + e);
}
}
@@ -116,7 +116,7 @@ public class RequestSessionMetric {
try {
mChosenProviderFinalPhaseMetric.setUiCallStartTimeNanoseconds(uiCallStartTime);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error collecting ui start metric: " + e);
}
}
@@ -132,7 +132,7 @@ public class RequestSessionMetric {
mChosenProviderFinalPhaseMetric.setUiReturned(uiReturned);
mChosenProviderFinalPhaseMetric.setUiCallEndTimeNanoseconds(uiEndTimestamp);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error collecting ui response metric: " + e);
}
}
@@ -146,7 +146,7 @@ public class RequestSessionMetric {
try {
mChosenProviderFinalPhaseMetric.setChosenProviderStatus(status);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error setting chosen provider status metric: " + e);
}
}
@@ -159,7 +159,7 @@ public class RequestSessionMetric {
try {
mInitialPhaseMetric.setOriginSpecified(origin);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error collecting create flow metric: " + e);
}
}
@@ -175,7 +175,7 @@ public class RequestSessionMetric {
uniqueRequestCounts.put(optionKey, uniqueRequestCounts.get(optionKey) + 1);
});
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during get request metric logging: " + e);
+ Slog.i(TAG, "Unexpected error during get request metric logging: " + e);
}
return uniqueRequestCounts;
}
@@ -190,7 +190,7 @@ public class RequestSessionMetric {
mInitialPhaseMetric.setOriginSpecified(request.getOrigin() != null);
mInitialPhaseMetric.setRequestCounts(getRequestCountMap(request));
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error collecting get flow metric: " + e);
}
}
@@ -213,7 +213,7 @@ public class RequestSessionMetric {
browsingPhaseMetric.setProviderUid(selectedProviderPhaseMetric.getCandidateUid());
mCandidateBrowsingPhaseMetric.add(browsingPhaseMetric);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error collecting browsing metric: " + e);
}
}
@@ -226,7 +226,7 @@ public class RequestSessionMetric {
try {
mChosenProviderFinalPhaseMetric.setHasException(exceptionBitFinalPhase);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error setting final exception metric: " + e);
}
}
@@ -244,7 +244,7 @@ public class RequestSessionMetric {
mChosenProviderFinalPhaseMetric.setChosenProviderStatus(
finalStatus.getMetricCode());
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error during metric logging: " + e);
}
}
@@ -272,24 +272,11 @@ public class RequestSessionMetric {
candidatePhaseMetric.getStartQueryTimeNanoseconds());
mChosenProviderFinalPhaseMetric.setQueryEndTimeNanoseconds(candidatePhaseMetric
.getQueryFinishTimeNanoseconds());
-
- mChosenProviderFinalPhaseMetric.setNumEntriesTotal(candidatePhaseMetric
- .getNumEntriesTotal());
- mChosenProviderFinalPhaseMetric.setCredentialEntryCount(candidatePhaseMetric
- .getCredentialEntryCount());
- mChosenProviderFinalPhaseMetric.setCredentialEntryTypeCount(
- candidatePhaseMetric.getCredentialEntryTypeCount());
- mChosenProviderFinalPhaseMetric.setActionEntryCount(candidatePhaseMetric
- .getActionEntryCount());
- mChosenProviderFinalPhaseMetric.setRemoteEntryCount(candidatePhaseMetric
- .getRemoteEntryCount());
- mChosenProviderFinalPhaseMetric.setAuthenticationEntryCount(
- candidatePhaseMetric.getAuthenticationEntryCount());
- mChosenProviderFinalPhaseMetric.setAvailableEntries(candidatePhaseMetric
- .getAvailableEntries());
+ mChosenProviderFinalPhaseMetric.setResponseCollective(
+ candidatePhaseMetric.getResponseCollective());
mChosenProviderFinalPhaseMetric.setFinalFinishTimeNanoseconds(System.nanoTime());
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error during metric candidate to final transfer: " + e);
}
}
@@ -312,7 +299,7 @@ public class RequestSessionMetric {
/* apiStatus */ ApiStatus.FAILURE.getMetricCode());
}
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error during final metric failure emit: " + e);
}
}
@@ -326,7 +313,7 @@ public class RequestSessionMetric {
try {
logApiCalledCandidatePhase(providers, ++mSequenceCounter, mInitialPhaseMetric);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error during candidate metric emit: " + e);
}
}
@@ -341,7 +328,7 @@ public class RequestSessionMetric {
apiStatus,
++mSequenceCounter);
} catch (Exception e) {
- Log.w(TAG, "Unexpected error during metric logging: " + e);
+ Slog.i(TAG, "Unexpected error during final metric emit: " + e);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/shared/ResponseCollective.java b/services/credentials/java/com/android/server/credentials/metrics/shared/ResponseCollective.java
new file mode 100644
index 000000000000..fd785c2f4dfc
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/metrics/shared/ResponseCollective.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.credentials.metrics.shared;
+
+import android.annotation.NonNull;
+
+import com.android.server.credentials.metrics.EntryEnum;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Some data is directly shared between the
+ * {@link com.android.server.credentials.metrics.CandidatePhaseMetric} and the
+ * {@link com.android.server.credentials.metrics.ChosenProviderFinalPhaseMetric}. This
+ * aims to create an abstraction that holds that information, to avoid duplication.
+ *
+ * This class should be immutable and threadsafe once generated.
+ */
+public class ResponseCollective {
+ /*
+ Abstract Function (responseCounts, entryCounts) -> A 'ResponseCollective' containing information
+ about a chosen or candidate providers available responses, be they entries or credentials.
+
+ RepInvariant: mResponseCounts and mEntryCounts are always initialized
+
+ Threadsafe and Immutability: Once generated, the maps remain unchangeable. The object is
+ threadsafe and immutable, and safe from external changes. This is threadsafe because it is
+ immutable after creation and only allows reads, not writes.
+ */
+
+ private static final String TAG = "ResponseCollective";
+
+ // Stores the deduped credential response information, eg {"response":5} for this provider
+ private final Map<String, Integer> mResponseCounts;
+ // Stores the deduped entry information, eg {ENTRY_ENUM:5} for this provider
+ private final Map<EntryEnum, Integer> mEntryCounts;
+
+ public ResponseCollective(@NonNull Map<String, Integer> responseCounts,
+ @NonNull Map<EntryEnum, Integer> entryCounts) {
+ mResponseCounts = responseCounts == null ? new LinkedHashMap<>() :
+ new LinkedHashMap<>(responseCounts);
+ mEntryCounts = entryCounts == null ? new LinkedHashMap<>() :
+ new LinkedHashMap<>(entryCounts);
+ }
+
+ /**
+ * Returns the unique, deduped, response classtypes for logging associated with this provider.
+ *
+ * @return a string array for deduped classtypes
+ */
+ public String[] getUniqueResponseStrings() {
+ String[] result = new String[mResponseCounts.keySet().size()];
+ mResponseCounts.keySet().toArray(result);
+ return result;
+ }
+
+ /**
+ * Returns the unique, deduped, response classtype counts for logging associated with this
+ * provider.
+ * @return a string array for deduped classtype counts
+ */
+ public int[] getUniqueResponseCounts() {
+ return mResponseCounts.values().stream().mapToInt(Integer::intValue).toArray();
+ }
+
+ /**
+ * Returns the unique, deduped, entry types for logging associated with this provider.
+ * @return an int array for deduped entries
+ */
+ public int[] getUniqueEntries() {
+ return mEntryCounts.keySet().stream().mapToInt(Enum::ordinal).toArray();
+ }
+
+ /**
+ * Returns the unique, deduped, entry classtype counts for logging associated with this
+ * provider.
+ * @return a string array for deduped classtype counts
+ */
+ public int[] getUniqueEntryCounts() {
+ return mEntryCounts.values().stream().mapToInt(Integer::intValue).toArray();
+ }
+
+ /**
+ * Given a specific {@link EntryEnum}, this provides us with the count of that entry within
+ * this particular provider.
+ * @param e the entry enum with which we want to know the count of
+ * @return a count of this particular entry enum stored by this provider
+ */
+ public int getCountForEntry(EntryEnum e) {
+ return mEntryCounts.get(e);
+ }
+
+ /**
+ * Indicates the total number of existing entries for this provider.
+ * @return a count of the total number of entries for this provider
+ */
+ public int getNumEntriesTotal() {
+ return mEntryCounts.values().stream().mapToInt(Integer::intValue).sum();
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index cf49dcf8004e..0c4830afafcc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -684,6 +684,38 @@ final class DevicePolicyEngine {
}
}
+ <V> void transferPolicies(EnforcingAdmin oldAdmin, EnforcingAdmin newAdmin) {
+ Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet());
+ for (PolicyKey policy : globalPolicies) {
+ PolicyState<?> policyState = mGlobalPolicies.get(policy);
+ if (policyState.getPoliciesSetByAdmins().containsKey(oldAdmin)) {
+ PolicyDefinition<V> policyDefinition =
+ (PolicyDefinition<V>) policyState.getPolicyDefinition();
+ PolicyValue<V> policyValue =
+ (PolicyValue<V>) policyState.getPoliciesSetByAdmins().get(oldAdmin);
+ setGlobalPolicy(policyDefinition, newAdmin, policyValue);
+ }
+ }
+
+ for (int i = 0; i < mLocalPolicies.size(); i++) {
+ int userId = mLocalPolicies.keyAt(i);
+ Set<PolicyKey> localPolicies = new HashSet<>(
+ mLocalPolicies.get(userId).keySet());
+ for (PolicyKey policy : localPolicies) {
+ PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
+ if (policyState.getPoliciesSetByAdmins().containsKey(oldAdmin)) {
+ PolicyDefinition<V> policyDefinition =
+ (PolicyDefinition<V>) policyState.getPolicyDefinition();
+ PolicyValue<V> policyValue =
+ (PolicyValue<V>) policyState.getPoliciesSetByAdmins().get(oldAdmin);
+ setLocalPolicy(policyDefinition, newAdmin, policyValue, userId);
+ }
+ }
+ }
+
+ removePoliciesForAdmin(oldAdmin);
+ }
+
private Set<UserRestrictionPolicyKey> getUserRestrictionPolicyKeysForAdminLocked(
Map<PolicyKey, PolicyState<?>> policies,
EnforcingAdmin admin) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 675ebd3ddd60..3578b16d62c6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3882,6 +3882,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final ActiveAdmin adminToTransfer = policy.mAdminMap.get(outgoingReceiver);
final int oldAdminUid = adminToTransfer.getUid();
+ if (isPolicyEngineForFinanceFlagEnabled() || isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin oldAdmin =
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ outgoingReceiver, userHandle, adminToTransfer);
+ EnforcingAdmin newAdmin =
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ incomingReceiver, userHandle, adminToTransfer);
+
+ mDevicePolicyEngine.transferPolicies(oldAdmin, newAdmin);
+ }
+
adminToTransfer.transfer(incomingDeviceInfo);
policy.mAdminMap.remove(outgoingReceiver);
policy.mAdminMap.put(incomingReceiver, adminToTransfer);
@@ -6051,7 +6062,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void lockNow(int flags, String callerPackageName, boolean parent) {
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(callerPackageName);
} else {
caller = getCallerIdentity();
@@ -6063,7 +6074,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ActiveAdmin admin;
// Make sure the caller has any active admin with the right policy or
// the required permission.
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
admin = enforcePermissionAndGetEnforcingAdmin(
/* admin= */ null,
/* permission= */ MANAGE_DEVICE_POLICY_LOCK,
@@ -8917,13 +8928,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
// The effect of this policy is device-wide.
enforcePermission(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
} else {
@@ -8951,13 +8962,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforceCanQuery(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
} else {
Objects.requireNonNull(who, "ComponentName is null");
@@ -8980,13 +8991,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
// The effect of this policy is device-wide.
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
@@ -9026,13 +9037,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
// The effect of this policy is device-wide.
enforceCanQuery(SET_TIME_ZONE, caller.getPackageName(), UserHandle.USER_ALL);
} else {
@@ -9335,7 +9346,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
@@ -9345,7 +9356,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int userHandle = caller.getUserId();
int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
synchronized (getLockObject()) {
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
// SUPPORT USES_POLICY_DISABLE_KEYGUARD_FEATURES
EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
who, MANAGE_DEVICE_POLICY_KEYGUARD, caller.getPackageName(),
@@ -9424,13 +9435,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (getLockObject()) {
if (who != null) {
- if (isPermissionCheckFlagEnabled()) {
- EnforcingAdmin admin = getEnforcingAdminForCaller(
- who, who.getPackageName());
+ if (isUnicornFlagEnabled()) {
+ EnforcingAdmin admin = getEnforcingAdminForPackage(
+ who, who.getPackageName(), userHandle);
Integer features = mDevicePolicyEngine.getLocalPolicySetByAdmin(
PolicyDefinition.KEYGUARD_DISABLED_FEATURES,
admin,
affectedUserId);
+
return features == null ? 0 : features;
} else {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
@@ -9438,7 +9450,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
Integer features = mDevicePolicyEngine.getResolvedPolicy(
PolicyDefinition.KEYGUARD_DISABLED_FEATURES,
affectedUserId);
@@ -9999,10 +10011,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"clearDeviceOwner can only be called by the device owner");
}
enforceUserUnlocked(deviceOwnerUserId);
- DevicePolicyData policy = getUserData(deviceOwnerUserId);
- if (policy.mPasswordTokenHandle != 0) {
- mLockPatternUtils.removeEscrowToken(policy.mPasswordTokenHandle, deviceOwnerUserId);
- }
final ActiveAdmin admin = getDeviceOwnerAdminLocked();
mInjector.binderWithCleanCallingIdentity(() -> {
@@ -10057,6 +10065,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
final DevicePolicyData policyData = getUserData(userId);
policyData.mCurrentInputMethodSet = false;
+ if (policyData.mPasswordTokenHandle != 0) {
+ mLockPatternUtils.removeEscrowToken(policyData.mPasswordTokenHandle, userId);
+ policyData.mPasswordTokenHandle = 0;
+ }
saveSettingsLocked(userId);
mPolicyCache.onUserRemoved(userId);
final DevicePolicyData systemPolicyData = getUserData(UserHandle.USER_SYSTEM);
@@ -10748,7 +10760,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@VisibleForTesting
boolean hasDeviceIdAccessUnchecked(String packageName, int uid) {
final int userId = UserHandle.getUserId(uid);
- if (isPermissionCheckFlagEnabled()) {
+ // TODO(b/280048070): Introduce a permission to handle device ID access
+ if (isPermissionCheckFlagEnabled()
+ && !(isUidProfileOwnerLocked(uid) || isUidDeviceOwnerLocked(uid))) {
return hasPermission(MANAGE_DEVICE_POLICY_CERTIFICATES, packageName, userId);
} else {
ComponentName deviceOwner = getDeviceOwnerComponent(true);
@@ -11635,7 +11649,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_APPLICATION_RESTRICTIONS);
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
@@ -13062,7 +13076,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
@@ -13132,7 +13146,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
ActiveAdmin admin;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
@@ -13229,7 +13243,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public boolean isPackageSuspended(ComponentName who, String callerPackage, String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforcePermission(
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
caller.getPackageName(),
@@ -13835,7 +13849,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean hidden, boolean parent) {
CallerIdentity caller = getCallerIdentity(who, callerPackage);
final int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
// TODO: We need to ensure the delegate with DELEGATION_PACKAGE_ACCESS can do this
enforcePermission(MANAGE_DEVICE_POLICY_PACKAGE_STATE, caller.getPackageName(), userId);
} else {
@@ -13854,7 +13868,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean result;
synchronized (getLockObject()) {
if (parent) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(
caller.getUserId()) && isManagedProfile(caller.getUserId()));
@@ -13871,7 +13885,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slogf.v(LOG_TAG, "calling pm.setApplicationHiddenSettingAsUser(%s, %b, %d)",
packageName, hidden, userId);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin admin = getEnforcingAdminForCaller(who, callerPackage);
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.APPLICATION_HIDDEN(packageName),
@@ -13910,7 +13924,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
String packageName, boolean parent) {
CallerIdentity caller = getCallerIdentity(who, callerPackage);
int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
// TODO: Also support DELEGATION_PACKAGE_ACCESS
enforcePermission(MANAGE_DEVICE_POLICY_PACKAGE_STATE, caller.getPackageName(), userId);
} else {
@@ -13922,7 +13936,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (getLockObject()) {
if (parent) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId())
&& isManagedProfile(caller.getUserId()));
@@ -14114,13 +14128,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
enforceMaxStringLength(accountType, "account type");
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
synchronized (getLockObject()) {
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
int affectedUser = getAffectedUser(parent);
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
@@ -14183,7 +14197,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
CallerIdentity caller;
Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
final ArraySet<String> resultSet = new ArraySet<>();
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
int affectedUser = parent ? getProfileParentId(userId) : userId;
caller = getCallerIdentity(callerPackageName);
if (!hasPermission(MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
@@ -15554,12 +15568,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public boolean setStatusBarDisabled(ComponentName who, String callerPackageName,
boolean disabled) {
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforcePermission(MANAGE_DEVICE_POLICY_STATUS_BAR, caller.getPackageName(),
UserHandle.USER_ALL);
} else {
@@ -15570,7 +15584,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int userId = caller.getUserId();
synchronized (getLockObject()) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isUnicornFlagEnabled()) {
Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
"Admin " + who + " is neither the device owner or affiliated "
+ "user's profile owner.");
@@ -15629,7 +15643,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public boolean isStatusBarDisabled(String callerPackage) {
final CallerIdentity caller = getCallerIdentity(callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforceCanQuery(
MANAGE_DEVICE_POLICY_STATUS_BAR, caller.getPackageName(), caller.getUserId());
} else {
@@ -15639,7 +15653,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int userId = caller.getUserId();
synchronized (getLockObject()) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isUnicornFlagEnabled()) {
Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
"Admin " + callerPackage
+ " is neither the device owner or affiliated user's profile owner.");
@@ -16800,7 +16814,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
EnforcingAdmin enforcingAdmin;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
@@ -16971,7 +16985,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public int getPermissionGrantState(ComponentName admin, String callerPackage,
String packageName, String permission) throws RemoteException {
final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforceCanQuery(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, caller.getPackageName(),
caller.getUserId());
} else {
@@ -19109,14 +19123,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new IllegalArgumentException("token must be at least 32-byte long");
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
}
final int userId = caller.getUserId();
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19172,7 +19186,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
@@ -19180,7 +19194,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int userId = caller.getUserId();
boolean result = false;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19219,14 +19233,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
}
int userId = caller.getUserId();
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19268,7 +19282,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Objects.requireNonNull(token);
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
@@ -19278,7 +19292,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean result = false;
final String password = passwordOrNull != null ? passwordOrNull : "";
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19309,7 +19323,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (result) {
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.RESET_PASSWORD_WITH_TOKEN)
.setAdmin(callerPackageName)
@@ -22930,6 +22944,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
MANAGE_DEVICE_POLICY_LOCATION,
MANAGE_DEVICE_POLICY_LOCK,
MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ MANAGE_DEVICE_POLICY_CERTIFICATES,
MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
@@ -23566,6 +23581,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
}
+ private EnforcingAdmin getEnforcingAdminForPackage(@Nullable ComponentName who,
+ String packageName, int userId) {
+ ActiveAdmin admin;
+ if (who != null) {
+ if (isDeviceOwner(who, userId) || isProfileOwner(who, userId)) {
+ synchronized (getLockObject()) {
+ admin = getActiveAdminUncheckedLocked(who, userId);
+ }
+ if (admin != null) {
+ return EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userId, admin);
+ }
+ } else {
+ // Check for non-DPC active admins.
+ admin = getActiveAdminUncheckedLocked(who, userId);
+ if (admin != null) {
+ return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
+ }
+ }
+ }
+
+ admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
+ return EnforcingAdmin.createEnforcingAdmin(packageName, userId, admin);
+ }
+
private int getAffectedUser(boolean calledOnParent) {
int callingUserId = mInjector.userHandleGetCallingUserId();
return calledOnParent ? getProfileParentId(callingUserId) : callingUserId;
@@ -23621,6 +23660,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DEFAULT_KEEP_PROFILES_RUNNING_FLAG);
}
+ private boolean isUnicornFlagEnabled() {
+ return false;
+ }
+
private boolean isWorkProfileTelephonyEnabled() {
return isWorkProfileTelephonyDevicePolicyManagerFlagEnabled()
&& isWorkProfileTelephonySubscriptionManagerFlagEnabled();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b1d613109e09..a8a1c0354cf4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -593,8 +593,8 @@ public final class SystemServer implements Dumpable {
* Spawn a thread that monitors for fd leaks.
*/
private static void spawnFdLeakCheckThread() {
- final int enableThreshold = SystemProperties.getInt(SYSPROP_FDTRACK_ENABLE_THRESHOLD, 1024);
- final int abortThreshold = SystemProperties.getInt(SYSPROP_FDTRACK_ABORT_THRESHOLD, 2048);
+ final int enableThreshold = SystemProperties.getInt(SYSPROP_FDTRACK_ENABLE_THRESHOLD, 1600);
+ final int abortThreshold = SystemProperties.getInt(SYSPROP_FDTRACK_ABORT_THRESHOLD, 3000);
final int checkInterval = SystemProperties.getInt(SYSPROP_FDTRACK_INTERVAL, 120);
new Thread(() -> {
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index f05b1d47ac0b..475966ea00b8 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -20,9 +20,11 @@ import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Handler;
import android.os.IBinder.DeathRecipient;
import android.os.Looper;
@@ -53,7 +55,8 @@ public final class ProfcollectForwardingService extends SystemService {
public static final String LOG_TAG = "ProfcollectForwardingService";
private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
-
+ private static final String INTENT_UPLOAD_PROFILES =
+ "com.android.server.profcollect.UPLOAD_PROFILES";
private static final long BG_PROCESS_PERIOD = TimeUnit.HOURS.toMillis(4); // every 4 hours.
private IProfCollectd mIProfcollect;
@@ -66,6 +69,16 @@ public final class ProfcollectForwardingService extends SystemService {
}
};
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction() == INTENT_UPLOAD_PROFILES) {
+ Log.d(LOG_TAG, "Received broadcast to pack and upload reports");
+ packAndUploadReport();
+ }
+ }
+ };
+
public ProfcollectForwardingService(Context context) {
super(context);
@@ -73,6 +86,10 @@ public final class ProfcollectForwardingService extends SystemService {
throw new AssertionError("only one service instance allowed");
}
sSelfService = this;
+
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(INTENT_UPLOAD_PROFILES);
+ context.registerReceiver(mBroadcastReceiver, filter);
}
/**
@@ -296,7 +313,7 @@ public final class ProfcollectForwardingService extends SystemService {
}
if (status == UpdateEngine.UpdateStatusConstants.UPDATED_NEED_REBOOT) {
- packProfileReport();
+ packAndUploadReport();
}
}
@@ -307,7 +324,7 @@ public final class ProfcollectForwardingService extends SystemService {
});
}
- private void packProfileReport() {
+ private void packAndUploadReport() {
if (mIProfcollect == null) {
return;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
index 941a3a419d59..3faf394fc534 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
@@ -72,18 +72,28 @@ public class DisplayWhiteBalanceTintControllerTest {
mResources = InstrumentationRegistry.getContext().getResources();
// These Resources are common to all tests.
- doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMin))
+ doReturn(4000)
.when(mMockedResources)
.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMin);
- doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMax))
+ doReturn(8000)
.when(mMockedResources)
.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMax);
- doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault))
+ doReturn(6500)
.when(mMockedResources)
.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault);
- doReturn(mResources.getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite))
- .when(mMockedResources)
- .getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite);
+ doReturn(new String[] {"0.950456", "1.000000", "1.089058"})
+ .when(mMockedResources)
+ .getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite);
+ doReturn(6500)
+ .when(mMockedResources)
+ .getInteger(R.integer.config_displayWhiteBalanceDisplayNominalWhiteCct);
+ doReturn(new int[] {0})
+ .when(mMockedResources)
+ .getIntArray(R.array.config_displayWhiteBalanceDisplaySteps);
+ doReturn(new int[] {20})
+ .when(mMockedResources)
+ .getIntArray(R.array.config_displayWhiteBalanceDisplayRangeMinimums);
+
doReturn(mMockedResources).when(mMockedContext).getResources();
mDisplayToken = new Binder();
@@ -195,7 +205,7 @@ public class DisplayWhiteBalanceTintControllerTest {
* Matrix should match the precalculated one for given cct and display primaries.
*/
@Test
- public void displayWhiteBalance_validateTransformMatrix() {
+ public void displayWhiteBalance_getAndSetMatrix_validateTransformMatrix() {
DisplayPrimaries displayPrimaries = new DisplayPrimaries();
displayPrimaries.red = new CieXyz();
displayPrimaries.red.X = 0.412315f;
@@ -223,10 +233,12 @@ public class DisplayWhiteBalanceTintControllerTest {
final int cct = 6500;
mDisplayWhiteBalanceTintController.setMatrix(cct);
+ mDisplayWhiteBalanceTintController.setAppliedCct(
+ mDisplayWhiteBalanceTintController.getTargetCct());
+
assertWithMessage("Failed to set temperature")
.that(mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
.isEqualTo(cct);
-
float[] matrixDwb = mDisplayWhiteBalanceTintController.getMatrix();
final float[] expectedMatrixDwb = {
0.971848f, -0.001421f, 0.000491f, 0.0f,
@@ -238,6 +250,54 @@ public class DisplayWhiteBalanceTintControllerTest {
1e-6f /* tolerance */);
}
+ /**
+ * Matrix should match the precalculated one for given cct and display primaries.
+ */
+ @Test
+ public void displayWhiteBalance_targetApplied_validateTransformMatrix() {
+ DisplayPrimaries displayPrimaries = new DisplayPrimaries();
+ displayPrimaries.red = new CieXyz();
+ displayPrimaries.red.X = 0.412315f;
+ displayPrimaries.red.Y = 0.212600f;
+ displayPrimaries.red.Z = 0.019327f;
+ displayPrimaries.green = new CieXyz();
+ displayPrimaries.green.X = 0.357600f;
+ displayPrimaries.green.Y = 0.715200f;
+ displayPrimaries.green.Z = 0.119200f;
+ displayPrimaries.blue = new CieXyz();
+ displayPrimaries.blue.X = 0.180500f;
+ displayPrimaries.blue.Y = 0.072200f;
+ displayPrimaries.blue.Z = 0.950633f;
+ displayPrimaries.white = new CieXyz();
+ displayPrimaries.white.X = 0.950456f;
+ displayPrimaries.white.Y = 1.000000f;
+ displayPrimaries.white.Z = 1.089058f;
+ when(mDisplayManagerInternal.getDisplayNativePrimaries(DEFAULT_DISPLAY))
+ .thenReturn(displayPrimaries);
+
+ setUpTintController();
+ assertWithMessage("Setup with valid SurfaceControl failed")
+ .that(mDisplayWhiteBalanceTintController.mSetUp)
+ .isTrue();
+
+ final int cct = 6500;
+ mDisplayWhiteBalanceTintController.setTargetCct(cct);
+ final float[] matrixDwb = mDisplayWhiteBalanceTintController.computeMatrixForCct(cct);
+ mDisplayWhiteBalanceTintController.setAppliedCct(cct);
+
+ assertWithMessage("Failed to set temperature")
+ .that(mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+ .isEqualTo(cct);
+ final float[] expectedMatrixDwb = {
+ 0.971848f, -0.001421f, 0.000491f, 0.0f,
+ 0.028193f, 0.945798f, 0.003207f, 0.0f,
+ -0.000042f, -0.000989f, 0.988659f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ assertArrayEquals("Unexpected DWB matrix", expectedMatrixDwb, matrixDwb,
+ 1e-6f /* tolerance */);
+ }
+
private void setUpTintController() {
mDisplayWhiteBalanceTintController = new DisplayWhiteBalanceTintController(
mDisplayManagerInternal);
diff --git a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
index f788c92b24b2..46974cf72381 100644
--- a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
@@ -28,6 +28,8 @@ import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
+import static com.android.server.am.ProcessList.UNKNOWN_ADJ;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
@@ -81,7 +83,7 @@ public class UidObserverControllerTest {
public void testEnqueueUidChange() {
int change = mUidObserverController.enqueueUidChange(null, TEST_UID1,
UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
- PROCESS_CAPABILITY_ALL, 0, false);
+ UNKNOWN_ADJ, PROCESS_CAPABILITY_ALL, 0, false);
assertEquals("expected=ACTIVE,actual=" + changeToStr(change),
UidRecord.CHANGE_ACTIVE, change);
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
@@ -91,8 +93,8 @@ public class UidObserverControllerTest {
final ChangeRecord record2 = new ChangeRecord();
change = mUidObserverController.enqueueUidChange(record2, TEST_UID2,
- UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT, PROCESS_CAPABILITY_NONE,
- 99, true);
+ UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT, UNKNOWN_ADJ,
+ PROCESS_CAPABILITY_NONE, 99, true);
assertEquals("expected=ACTIVE,actual=" + changeToStr(change),
UidRecord.CHANGE_CACHED, change);
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
@@ -101,7 +103,8 @@ public class UidObserverControllerTest {
PROCESS_CAPABILITY_NONE, 99, true, record2);
change = mUidObserverController.enqueueUidChange(record1, TEST_UID1,
- UidRecord.CHANGE_UNCACHED, PROCESS_STATE_TOP, PROCESS_CAPABILITY_ALL, 0, false);
+ UidRecord.CHANGE_UNCACHED, PROCESS_STATE_TOP, UNKNOWN_ADJ,
+ PROCESS_CAPABILITY_ALL, 0, false);
assertEquals("expected=ACTIVE|UNCACHED,actual=" + changeToStr(change),
UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED, change);
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED,
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index d12741ac8bd6..cbc7dc2f2fe5 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -100,6 +100,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.server.FgThread;
import com.android.server.SystemService;
import com.android.server.am.UserState.KeyEvictedCallback;
+import com.android.server.pm.UserJourneyLogger;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.wm.WindowManagerService;
@@ -1074,6 +1075,8 @@ public class UserControllerTest {
private final KeyguardManager mKeyguardManagerMock;
private final LockPatternUtils mLockPatternUtilsMock;
+ private final UserJourneyLogger mUserJourneyLoggerMock;
+
private final Context mCtx;
TestInjector(Context ctx) {
@@ -1090,6 +1093,7 @@ public class UserControllerTest {
mKeyguardManagerMock = mock(KeyguardManager.class);
when(mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true);
mLockPatternUtilsMock = mock(LockPatternUtils.class);
+ mUserJourneyLoggerMock = mock(UserJourneyLogger.class);
}
@Override
@@ -1220,6 +1224,11 @@ public class UserControllerTest {
void onSystemUserVisibilityChanged(boolean visible) {
Log.i(TAG, "onSystemUserVisibilityChanged(" + visible + ")");
}
+
+ @Override
+ protected UserJourneyLogger getUserJourneyLogger() {
+ return mUserJourneyLoggerMock;
+ }
}
private static class TestHandler extends Handler {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorListTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorListTest.java
new file mode 100644
index 000000000000..3d80916bd63e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorListTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.app.IActivityManager;
+import android.app.SynchronousUserSwitchObserver;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.biometrics.sensors.face.aidl.Sensor;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@Presubmit
+@SmallTest
+public class SensorListTest {
+ @Rule
+ public MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Mock
+ Sensor mSensor;
+ @Mock
+ IActivityManager mActivityManager;
+ @Mock
+ SynchronousUserSwitchObserver mUserSwitchObserver;
+
+ SensorList<Sensor> mSensorList;
+
+ @Before
+ public void setUp() throws RemoteException {
+ mSensorList = new SensorList<>(mActivityManager);
+ }
+
+ @Test
+ public void testAddingSensor() throws RemoteException {
+ mSensorList.addSensor(0, mSensor, UserHandle.USER_NULL, mUserSwitchObserver);
+
+ verify(mUserSwitchObserver).onUserSwitching(UserHandle.USER_SYSTEM);
+ verify(mActivityManager).registerUserSwitchObserver(eq(mUserSwitchObserver), anyString());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
index 41f743367aeb..31a58cd67d3e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.face.aidl;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -30,6 +32,7 @@ import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.SensorProps;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
@@ -38,6 +41,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -98,16 +102,34 @@ public class FaceProviderTest {
mSensorProps, TAG, mLockoutResetDispatcher, mBiometricContext);
}
+ @Test
+ public void testAddingSensors() {
+ waitForIdle();
+
+ for (SensorProps prop : mSensorProps) {
+ final BiometricScheduler scheduler =
+ mFaceProvider.mFaceSensors.get(prop.commonProps.sensorId)
+ .getScheduler();
+ BaseClientMonitor currentClient = scheduler.getCurrentClient();
+
+ assertThat(currentClient).isInstanceOf(FaceInternalCleanupClient.class);
+ assertThat(currentClient.getSensorId()).isEqualTo(prop.commonProps.sensorId);
+ assertThat(currentClient.getTargetUserId()).isEqualTo(UserHandle.USER_SYSTEM);
+ }
+ }
+
@SuppressWarnings("rawtypes")
@Test
public void halServiceDied_resetsAllSchedulers() {
+ waitForIdle();
+
assertEquals(mSensorProps.length, mFaceProvider.getSensorProperties().size());
// Schedule N operations on each sensor
final int numFakeOperations = 10;
for (SensorProps prop : mSensorProps) {
final BiometricScheduler scheduler =
- mFaceProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
+ mFaceProvider.mFaceSensors.get(prop.commonProps.sensorId).getScheduler();
for (int i = 0; i < numFakeOperations; i++) {
final HalClientMonitor testMonitor = mock(HalClientMonitor.class);
when(testMonitor.getFreshDaemon()).thenReturn(new Object());
@@ -119,8 +141,8 @@ public class FaceProviderTest {
// The right amount of pending and current operations are scheduled
for (SensorProps prop : mSensorProps) {
final BiometricScheduler scheduler =
- mFaceProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
- assertEquals(numFakeOperations - 1, scheduler.getCurrentPendingCount());
+ mFaceProvider.mFaceSensors.get(prop.commonProps.sensorId).getScheduler();
+ assertEquals(numFakeOperations, scheduler.getCurrentPendingCount());
assertNotNull(scheduler.getCurrentClient());
}
@@ -132,7 +154,7 @@ public class FaceProviderTest {
// No pending operations, no current operation.
for (SensorProps prop : mSensorProps) {
final BiometricScheduler scheduler =
- mFaceProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
+ mFaceProvider.mFaceSensors.get(prop.commonProps.sensorId).getScheduler();
assertNull(scheduler.getCurrentClient());
assertEquals(0, scheduler.getCurrentPendingCount());
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
index 9c9d3f894d95..25bd9bcf8d5c 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
@@ -29,9 +29,9 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.common.CommonProps;
-import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.SensorProps;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.os.Handler;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
@@ -42,7 +42,6 @@ import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.BiometricScheduler;
-import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -82,17 +81,13 @@ public class SensorTest {
@Mock
private AuthSessionCoordinator mAuthSessionCoordinator;
@Mock
- private IFace mDaemon;
- @Mock
- private BiometricStateCallback mBiometricStateCallback;
+ FaceProvider mFaceProvider;
private final TestLooper mLooper = new TestLooper();
private final LockoutCache mLockoutCache = new LockoutCache();
private UserAwareBiometricScheduler mScheduler;
private Sensor.HalSessionCallback mHalCallback;
- private FaceProvider mFaceProvider;
- private SensorProps[] mSensorProps;
@Before
public void setUp() {
@@ -113,16 +108,6 @@ public class SensorTest {
TAG, mScheduler, SENSOR_ID,
USER_ID, mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator,
mHalSessionCallback);
-
- final SensorProps sensor1 = new SensorProps();
- sensor1.commonProps = new CommonProps();
- sensor1.commonProps.sensorId = 0;
- final SensorProps sensor2 = new SensorProps();
- sensor2.commonProps = new CommonProps();
- sensor2.commonProps.sensorId = 1;
- mSensorProps = new SensorProps[]{sensor1, sensor2};
- mFaceProvider = new FaceProvider(mContext, mBiometricStateCallback,
- mSensorProps, TAG, mLockoutResetDispatcher, mBiometricContext);
}
@Test
@@ -154,14 +139,26 @@ public class SensorTest {
@Test
public void onBinderDied_noErrorOnNullClient() {
+ mLooper.dispatchAll();
+
+ final SensorProps sensorProps = new SensorProps();
+ sensorProps.commonProps = new CommonProps();
+ sensorProps.commonProps.sensorId = 1;
+ final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
+ sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
+ sensorProps.commonProps.maxEnrollmentsPerUser, null,
+ sensorProps.sensorType, sensorProps.supportsDetectInteraction,
+ sensorProps.halControlsPreview, false /* resetLockoutRequiresChallenge */);
+ final Sensor sensor = new Sensor("SensorTest", mFaceProvider, mContext, null,
+ internalProp, mLockoutResetDispatcher, mBiometricContext);
+
mScheduler.reset();
+
assertNull(mScheduler.getCurrentClient());
- mFaceProvider.binderDied();
- for (int i = 0; i < mFaceProvider.mSensors.size(); i++) {
- final Sensor sensor = mFaceProvider.mSensors.valueAt(i);
- assertNull(sensor.getSessionForUser(USER_ID));
- }
+ sensor.onBinderDied();
+
+ assertNull(sensor.getSessionForUser(USER_ID));
}
private void verifyNotLocked() {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index c6ddf27f96b2..9c01de6f0461 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -33,6 +35,7 @@ import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.SensorLocation;
import android.hardware.biometrics.fingerprint.SensorProps;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
@@ -41,6 +44,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -111,16 +115,38 @@ public class FingerprintProviderTest {
mGestureAvailabilityDispatcher, mBiometricContext);
}
+ @Test
+ public void testAddingSensors() {
+ mFingerprintProvider = new TestableFingerprintProvider(mDaemon, mContext,
+ mBiometricStateCallback, mSensorProps, TAG, mLockoutResetDispatcher,
+ mGestureAvailabilityDispatcher, mBiometricContext);
+
+ waitForIdle();
+
+ for (SensorProps prop : mSensorProps) {
+ final BiometricScheduler scheduler =
+ mFingerprintProvider.mFingerprintSensors.get(prop.commonProps.sensorId)
+ .getScheduler();
+ BaseClientMonitor currentClient = scheduler.getCurrentClient();
+
+ assertThat(currentClient).isInstanceOf(FingerprintInternalCleanupClient.class);
+ assertThat(currentClient.getSensorId()).isEqualTo(prop.commonProps.sensorId);
+ assertThat(currentClient.getTargetUserId()).isEqualTo(UserHandle.USER_SYSTEM);
+ }
+ }
+
@SuppressWarnings("rawtypes")
@Test
public void halServiceDied_resetsAllSchedulers() {
+ waitForIdle();
assertEquals(mSensorProps.length, mFingerprintProvider.getSensorProperties().size());
// Schedule N operations on each sensor
final int numFakeOperations = 10;
for (SensorProps prop : mSensorProps) {
final BiometricScheduler scheduler =
- mFingerprintProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
+ mFingerprintProvider.mFingerprintSensors.get(prop.commonProps.sensorId)
+ .getScheduler();
for (int i = 0; i < numFakeOperations; i++) {
final HalClientMonitor testMonitor = mock(HalClientMonitor.class);
when(testMonitor.getFreshDaemon()).thenReturn(new Object());
@@ -132,8 +158,9 @@ public class FingerprintProviderTest {
// The right amount of pending and current operations are scheduled
for (SensorProps prop : mSensorProps) {
final BiometricScheduler scheduler =
- mFingerprintProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
- assertEquals(numFakeOperations - 1, scheduler.getCurrentPendingCount());
+ mFingerprintProvider.mFingerprintSensors.get(prop.commonProps.sensorId)
+ .getScheduler();
+ assertEquals(numFakeOperations, scheduler.getCurrentPendingCount());
assertNotNull(scheduler.getCurrentClient());
}
@@ -145,7 +172,8 @@ public class FingerprintProviderTest {
// No pending operations, no current operation.
for (SensorProps prop : mSensorProps) {
final BiometricScheduler scheduler =
- mFingerprintProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
+ mFingerprintProvider.mFingerprintSensors.get(prop.commonProps.sensorId)
+ .getScheduler();
assertNull(scheduler.getCurrentClient());
assertEquals(0, scheduler.getCurrentPendingCount());
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
index c5a9af7d909d..dcd06c9cc716 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
@@ -30,7 +30,7 @@ public class CallMetadataSyncDataTest {
@Test
public void call_writeToParcel_fromParcel_reconstructsSuccessfully() {
final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
- final long id = 5;
+ final String id = "5";
final String callerId = "callerId";
final byte[] appIcon = "appIcon".getBytes();
final String appName = "appName";
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java
index a488ab446aff..afddf3c9be29 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java
@@ -47,24 +47,24 @@ public class CallMetadataSyncInCallServiceTest {
@Test
public void getCallForId_invalid() {
- when(mMockCrossDeviceCall.getId()).thenReturn(-1L);
- final CrossDeviceCall call = mSyncInCallService.getCallForId(-1L,
+ when(mMockCrossDeviceCall.getId()).thenReturn(null);
+ final CrossDeviceCall call = mSyncInCallService.getCallForId(null,
List.of(mMockCrossDeviceCall));
assertWithMessage("Unexpectedly found a match for call id").that(call).isNull();
}
@Test
public void getCallForId_noMatch() {
- when(mMockCrossDeviceCall.getId()).thenReturn(5L);
- final CrossDeviceCall call = mSyncInCallService.getCallForId(1L,
+ when(mMockCrossDeviceCall.getId()).thenReturn("123abc");
+ final CrossDeviceCall call = mSyncInCallService.getCallForId("abc123",
List.of(mMockCrossDeviceCall));
assertWithMessage("Unexpectedly found a match for call id").that(call).isNull();
}
@Test
public void getCallForId_hasMatch() {
- when(mMockCrossDeviceCall.getId()).thenReturn(5L);
- final CrossDeviceCall call = mSyncInCallService.getCallForId(5L,
+ when(mMockCrossDeviceCall.getId()).thenReturn("123abc");
+ final CrossDeviceCall call = mSyncInCallService.getCallForId("123abc",
List.of(mMockCrossDeviceCall));
assertWithMessage("Unexpectedly did not find a match for call id").that(call).isNotNull();
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
index 9d42a5bf05d2..5a0646c0e0e5 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
@@ -62,9 +62,9 @@ public class CrossDeviceCallTest {
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.RINGING);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
- android.companion.Telecom.Call.REJECT,
- android.companion.Telecom.Call.SILENCE));
+ .isEqualTo(Set.of(android.companion.Telecom.ACCEPT,
+ android.companion.Telecom.REJECT,
+ android.companion.Telecom.SILENCE));
}
@Test
@@ -77,9 +77,9 @@ public class CrossDeviceCallTest {
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ONGOING);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.MUTE,
- android.companion.Telecom.Call.PUT_ON_HOLD));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.MUTE,
+ android.companion.Telecom.PUT_ON_HOLD));
}
@Test
@@ -92,8 +92,8 @@ public class CrossDeviceCallTest {
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ON_HOLD);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.TAKE_OFF_HOLD));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.TAKE_OFF_HOLD));
}
@Test
@@ -106,8 +106,8 @@ public class CrossDeviceCallTest {
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ONGOING);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.MUTE));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.MUTE));
}
@Test
@@ -120,8 +120,8 @@ public class CrossDeviceCallTest {
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ONGOING);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.PUT_ON_HOLD));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.PUT_ON_HOLD));
}
@Test
@@ -134,17 +134,17 @@ public class CrossDeviceCallTest {
assertWithMessage("Wrong status for ringing state").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.RINGING);
assertWithMessage("Wrong controls for ringing state").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
- android.companion.Telecom.Call.REJECT,
- android.companion.Telecom.Call.SILENCE));
+ .isEqualTo(Set.of(android.companion.Telecom.ACCEPT,
+ android.companion.Telecom.REJECT,
+ android.companion.Telecom.SILENCE));
crossDeviceCall.updateCallDetails(createCallDetails(Call.STATE_ACTIVE,
Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE));
assertWithMessage("Wrong status for active state").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ONGOING);
assertWithMessage("Wrong controls for active state").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.MUTE,
- android.companion.Telecom.Call.PUT_ON_HOLD));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.MUTE,
+ android.companion.Telecom.PUT_ON_HOLD));
}
@Test
@@ -158,8 +158,8 @@ public class CrossDeviceCallTest {
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.RINGING_SILENCED);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
- android.companion.Telecom.Call.REJECT));
+ .isEqualTo(Set.of(android.companion.Telecom.ACCEPT,
+ android.companion.Telecom.REJECT));
}
@Test
@@ -173,9 +173,9 @@ public class CrossDeviceCallTest {
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ONGOING);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.MUTE,
- android.companion.Telecom.Call.PUT_ON_HOLD));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.MUTE,
+ android.companion.Telecom.PUT_ON_HOLD));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
index eec026ccfc8a..25b0ae486230 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
@@ -81,7 +81,7 @@ public class CrossDeviceSyncControllerTest {
@Test
public void processTelecomDataFromSync_createCallUpdateMessage_hasCalls() {
- when(mMockCrossDeviceCall.getId()).thenReturn(5L);
+ when(mMockCrossDeviceCall.getId()).thenReturn("123abc");
final String callerId = "Firstname Lastname";
when(mMockCrossDeviceCall.getReadableCallerId(anyBoolean())).thenReturn(callerId);
final String appName = "AppName";
@@ -90,9 +90,9 @@ public class CrossDeviceSyncControllerTest {
when(mMockCrossDeviceCall.getCallingAppIcon()).thenReturn(appIcon.getBytes());
when(mMockCrossDeviceCall.getStatus()).thenReturn(android.companion.Telecom.Call.RINGING);
final Set<Integer> controls = Set.of(
- android.companion.Telecom.Call.ACCEPT,
- android.companion.Telecom.Call.REJECT,
- android.companion.Telecom.Call.SILENCE);
+ android.companion.Telecom.ACCEPT,
+ android.companion.Telecom.REJECT,
+ android.companion.Telecom.SILENCE);
when(mMockCrossDeviceCall.getControls()).thenReturn(controls);
final byte[] data = mCrossDeviceSyncController.createCallUpdateMessage(
new HashSet<>(List.of(mMockCrossDeviceCall)),
@@ -103,35 +103,33 @@ public class CrossDeviceSyncControllerTest {
callMetadataSyncData.getCalls()).hasSize(1);
final CallMetadataSyncData.Call call =
callMetadataSyncData.getCalls().stream().findAny().orElseThrow();
- assertWithMessage("Wrong id").that(call.getId()).isEqualTo(5L);
+ assertWithMessage("Wrong id").that(call.getId()).isEqualTo("123abc");
assertWithMessage("Wrong app icon").that(new String(call.getAppIcon())).isEqualTo(appIcon);
assertWithMessage("Wrong app name").that(call.getAppName()).isEqualTo(appName);
assertWithMessage("Wrong caller id").that(call.getCallerId()).isEqualTo(callerId);
assertWithMessage("Wrong status").that(call.getStatus())
.isEqualTo(android.companion.Telecom.Call.RINGING);
assertWithMessage("Wrong controls").that(call.getControls()).isEqualTo(controls);
- assertWithMessage("Unexpectedly has requests").that(
- callMetadataSyncData.getRequests()).isEmpty();
}
@Test
public void processTelecomDataFromMessage_createCallControlMessage_hasCallControlRequest() {
final byte[] data = CrossDeviceSyncController.createCallControlMessage(
- /* callId= */ 5L, /* status= */ android.companion.Telecom.Call.ACCEPT);
+ /* callId= */ "123abc", /* status= */ android.companion.Telecom.ACCEPT);
final CallMetadataSyncData callMetadataSyncData =
mCrossDeviceSyncController.processTelecomDataFromSync(data);
assertWithMessage("Wrong number of requests").that(
callMetadataSyncData.getRequests()).hasSize(1);
final CallMetadataSyncData.Call call =
callMetadataSyncData.getRequests().stream().findAny().orElseThrow();
- assertWithMessage("Wrong id").that(call.getId()).isEqualTo(5L);
+ assertWithMessage("Wrong id").that(call.getId()).isEqualTo("123abc");
assertWithMessage("Wrong app icon").that(call.getAppIcon()).isNull();
assertWithMessage("Wrong app name").that(call.getAppName()).isNull();
assertWithMessage("Wrong caller id").that(call.getCallerId()).isNull();
assertWithMessage("Wrong status").that(call.getStatus())
.isEqualTo(android.companion.Telecom.Call.UNKNOWN_STATUS);
assertWithMessage("Wrong controls").that(call.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT));
+ .isEqualTo(Set.of(android.companion.Telecom.ACCEPT));
assertWithMessage("Unexpectedly has active calls").that(
callMetadataSyncData.getCalls()).isEmpty();
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 1e342f580745..57755a9525fc 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1512,6 +1512,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
* Validates that when the device owner is removed, the reset password token is cleared
*/
@Test
+ @Ignore("b/277916462")
public void testClearDeviceOwner_clearResetPasswordToken() throws Exception {
mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
@@ -2602,6 +2603,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetApplicationHiddenWithDO() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -2627,6 +2629,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetApplicationHiddenWithPOOfOrganizationOwnedDevice() throws Exception {
final int MANAGED_PROFILE_USER_ID = CALLER_USER_HANDLE;
final int MANAGED_PROFILE_ADMIN_UID =
@@ -4373,6 +4376,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledModifiesSetting() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -4384,6 +4388,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledWithPOOnUser0() throws Exception {
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
setupProfileOwnerOnUser0();
@@ -4395,6 +4400,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledFailWithPONotOnUser0() throws Exception {
setupProfileOwner();
assertExpectException(SecurityException.class, null,
@@ -4404,6 +4410,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
@@ -5377,6 +5384,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testResetPasswordWithToken() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -5411,6 +5419,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void resetPasswordWithToken_NumericPin() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -5431,6 +5440,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void resetPasswordWithToken_EmptyPassword() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -7251,6 +7261,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testCanProfileOwnerResetPasswordWhenLocked() throws Exception {
setDeviceEncryptionPerUser();
setupProfileOwner();
@@ -7314,6 +7325,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetAccountTypesWithManagementDisabledOnManagedProfile() throws Exception {
setupProfileOwner();
@@ -7333,6 +7345,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetAccountTypesWithManagementDisabledOnOrgOwnedManagedProfile()
throws Exception {
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
diff --git a/services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java
new file mode 100644
index 000000000000..b96666ae40a3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.color;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CctEvaluatorTest {
+
+ @Test
+ public void noEntriesInParallelArrays_setsEverythingToOne() {
+ final CctEvaluator evaluator = new CctEvaluator(0, 5, new int[]{}, new int[]{});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{1, 1, 1, 1, 1, 1});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{0, 1, 2, 3, 4, 5});
+ }
+
+ @Test
+ public void unevenNumberOfEntriesInParallelArrays_setsEverythingToOne() {
+ final CctEvaluator evaluator = new CctEvaluator(0, 5, new int[]{0}, new int[]{});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{1, 1, 1, 1, 1, 1});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{0, 1, 2, 3, 4, 5});
+ }
+
+ @Test
+ public void singleEntryInParallelArray_computesCorrectly() {
+ final CctEvaluator evaluator = new CctEvaluator(0, 5, new int[]{0}, new int[]{2});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{2, 2, 2, 2, 2, 2});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{0, 0, 2, 2, 4, 4});
+ }
+
+ @Test
+ public void minimumIsBelowFirstRange_computesCorrectly() {
+ final CctEvaluator evaluator = new CctEvaluator(3000, 3005, new int[]{3002},
+ new int[]{20});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{20, 20, 20, 20, 20, 20});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{3000, 3000, 3000, 3000, 3000, 3000});
+ }
+
+ @Test
+ public void minimumIsAboveFirstRange_computesCorrectly() {
+ final CctEvaluator evaluator = new CctEvaluator(3000, 3008, new int[]{3002},
+ new int[]{20});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(
+ new int[]{20, 20, 20, 20, 20, 20, 20, 20, 20});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000});
+ }
+
+ @Test
+ public void multipleStepsStartsAtThreshold_computesCorrectly() {
+ final CctEvaluator evaluator = new CctEvaluator(5, 20, new int[]{0, 4, 5, 10, 18},
+ new int[]{11, 7, 2, 15, 9});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(
+ new int[]{2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 9, 9, 9});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{5, 5, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18});
+ }
+
+ @Test
+ public void multipleStepsStartsInBetween_computesCorrectly() {
+ final CctEvaluator evaluator = new CctEvaluator(4, 20, new int[]{0, 5, 10, 18},
+ new int[]{14, 2, 15, 9});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(
+ new int[]{14, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 9, 9, 9});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 18, 18, 18});
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
index d0d28c3f7ec0..55c45df2b844 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
@@ -85,6 +85,9 @@ class KeyboardLayoutManagerTests {
const val DEVICE_ID = 1
const val VENDOR_SPECIFIC_DEVICE_ID = 2
const val ENGLISH_DVORAK_DEVICE_ID = 3
+ const val ENGLISH_QWERTY_DEVICE_ID = 4
+ const val DEFAULT_VENDOR_ID = 123
+ const val DEFAULT_PRODUCT_ID = 456
const val USER_ID = 4
const val IME_ID = "ime_id"
const val PACKAGE_NAME = "KeyboardLayoutManagerTests"
@@ -122,6 +125,7 @@ class KeyboardLayoutManagerTests {
private lateinit var keyboardDevice: InputDevice
private lateinit var vendorSpecificKeyboardDevice: InputDevice
private lateinit var englishDvorakKeyboardDevice: InputDevice
+ private lateinit var englishQwertyKeyboardDevice: InputDevice
@Before
fun setup() {
@@ -150,17 +154,26 @@ class KeyboardLayoutManagerTests {
Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
.thenReturn(inputManager)
- keyboardDevice = createKeyboard(DEVICE_ID, 0, 0, "", "")
+ keyboardDevice = createKeyboard(DEVICE_ID, DEFAULT_VENDOR_ID, DEFAULT_PRODUCT_ID, "", "")
vendorSpecificKeyboardDevice = createKeyboard(VENDOR_SPECIFIC_DEVICE_ID, 1, 1, "", "")
- englishDvorakKeyboardDevice =
- createKeyboard(ENGLISH_DVORAK_DEVICE_ID, 0, 0, "en", "dvorak")
+ englishDvorakKeyboardDevice = createKeyboard(ENGLISH_DVORAK_DEVICE_ID, DEFAULT_VENDOR_ID,
+ DEFAULT_PRODUCT_ID, "en", "dvorak")
+ englishQwertyKeyboardDevice = createKeyboard(ENGLISH_QWERTY_DEVICE_ID, DEFAULT_VENDOR_ID,
+ DEFAULT_PRODUCT_ID, "en", "qwerty")
Mockito.`when`(iInputManager.inputDeviceIds)
- .thenReturn(intArrayOf(DEVICE_ID, VENDOR_SPECIFIC_DEVICE_ID, ENGLISH_DVORAK_DEVICE_ID))
+ .thenReturn(intArrayOf(
+ DEVICE_ID,
+ VENDOR_SPECIFIC_DEVICE_ID,
+ ENGLISH_DVORAK_DEVICE_ID,
+ ENGLISH_QWERTY_DEVICE_ID
+ ))
Mockito.`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardDevice)
Mockito.`when`(iInputManager.getInputDevice(VENDOR_SPECIFIC_DEVICE_ID))
.thenReturn(vendorSpecificKeyboardDevice)
Mockito.`when`(iInputManager.getInputDevice(ENGLISH_DVORAK_DEVICE_ID))
.thenReturn(englishDvorakKeyboardDevice)
+ Mockito.`when`(iInputManager.getInputDevice(ENGLISH_QWERTY_DEVICE_ID))
+ .thenReturn(englishQwertyKeyboardDevice)
}
private fun setupBroadcastReceiver() {
@@ -778,14 +791,23 @@ class KeyboardLayoutManagerTests {
@Test
fun testNewUi_getDefaultKeyboardLayoutForInputDevice_withHwLanguageTagAndLayoutType() {
NewSettingsApiFlag(true).use {
- // Should return English dvorak even if IME current layout is qwerty, since HW says the
+ val frenchSubtype = createImeSubtypeForLanguageTagAndLayoutType("fr", "azerty")
+ // Should return English dvorak even if IME current layout is French, since HW says the
// keyboard is a Dvorak keyboard
assertCorrectLayout(
englishDvorakKeyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("en", "qwerty"),
+ frenchSubtype,
createLayoutDescriptor("keyboard_layout_english_us_dvorak")
)
+ // Back to back changing HW keyboards with same product and vendor ID but different
+ // language and layout type should configure the layouts correctly.
+ assertCorrectLayout(
+ englishQwertyKeyboardDevice,
+ frenchSubtype,
+ createLayoutDescriptor("keyboard_layout_english_us")
+ )
+
// Fallback to IME information if the HW provided layout script is incompatible with the
// provided IME subtype
assertCorrectLayout(
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
index d07831dd7929..fd65807a1976 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
@@ -20,16 +20,25 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class InputMethodManagerServiceTests {
@@ -87,4 +96,25 @@ public class InputMethodManagerServiceTests {
InputMethodManagerService.computeImeDisplayIdForTarget(
SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, sChecker));
}
+
+ @Test
+ public void testSoftInputShowHideHistoryDump_withNulls_doesntThrow() {
+ var writer = new StringWriter();
+ var history = new InputMethodManagerService.SoftInputShowHideHistory();
+ history.addEntry(new InputMethodManagerService.SoftInputShowHideHistory.Entry(
+ null,
+ null,
+ null,
+ SOFT_INPUT_STATE_UNSPECIFIED,
+ SoftInputShowHideReason.SHOW_SOFT_INPUT,
+ false,
+ null,
+ null,
+ null,
+ null));
+
+ history.dump(new PrintWriter(writer), "" /* prefix */);
+
+ // Asserts that dump doesn't throw an NPE.
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index e65f8cf2a199..7c1845fcd54e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -201,7 +201,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL + 50;
assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
- mService.saveBaseStateLocked();
+ mService.saveBaseState();
dumpBaseStateFile();
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 01e56a0ddae6..1cfaf7c83584 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -228,6 +228,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
});
}
+ public void testShortcutIdTruncated() {
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(),
+ "s".repeat(Short.MAX_VALUE)).build();
+
+ assertTrue(
+ "id must be truncated to MAX_ID_LENGTH",
+ si.getId().length() <= ShortcutInfo.MAX_ID_LENGTH);
+ }
+
public void testShortcutInfoParcel() {
setCaller(CALLING_PACKAGE_1, USER_10);
ShortcutInfo si = parceled(new ShortcutInfo.Builder(mClientContext)
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserJourneyLoggerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserJourneyLoggerTest.java
new file mode 100644
index 000000000000..20e2692cb747
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserJourneyLoggerTest.java
@@ -0,0 +1,580 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_ABORTED;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_INCOMPLETE_OR_TIMEOUT;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_NULL_USER_INFO;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_UNSPECIFIED;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_BEGIN;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_CANCEL;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_ERROR;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_FINISH;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_NONE;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_GRANT_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_CREATE;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_REMOVE;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_START;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_STOP;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_CREATE_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_REMOVE_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_REVOKE_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_START_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_STOP_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.pm.UserInfo;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class UserJourneyLoggerTest {
+
+ public static final int FULL_USER_ADMIN_FLAG = 0x00000402;
+ private UserJourneyLogger mUserJourneyLogger;
+
+ @Before
+ public void setup() throws Exception {
+ mUserJourneyLogger = spy(new UserJourneyLogger());
+ }
+
+ @Test
+ public void testUserStartLifecycleJourneyReported() {
+ final UserLifecycleJourneyReportedCaptor report1 = new UserLifecycleJourneyReportedCaptor();
+ final UserJourneyLogger.UserJourneySession session = new UserJourneyLogger
+ .UserJourneySession(10, USER_JOURNEY_USER_START);
+
+ report1.captureLogAndAssert(mUserJourneyLogger, session,
+ USER_JOURNEY_USER_START, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY, 1,
+ ERROR_CODE_UNSPECIFIED);
+ }
+
+
+ @Test
+ public void testUserLifecycleEventOccurred() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = new UserJourneyLogger
+ .UserJourneySession(10, USER_JOURNEY_USER_START);
+
+ report1.captureLogAndAssert(mUserJourneyLogger, session, 0,
+ USER_LIFECYCLE_EVENT_START_USER, EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED);
+ }
+
+ @Test
+ public void testLogUserLifecycleEvent() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_START_USER, EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ mUserJourneyLogger.logUserLifecycleEvent(10, USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
+ EVENT_STATE_NONE);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
+ EVENT_STATE_NONE, ERROR_CODE_UNSPECIFIED, 2);
+ }
+
+
+ @Test
+ public void testCreateUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(-1, USER_JOURNEY_USER_CREATE);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, -1,
+ USER_LIFECYCLE_EVENT_CREATE_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserCreateJourneyFinish(0, targetUser);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_CREATE_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_CREATE, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testRemoveUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_REMOVE);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_REMOVE_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(0, targetUser,
+ USER_JOURNEY_USER_REMOVE);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_REMOVE_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_REMOVE, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testStartUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(0, targetUser,
+ USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_START, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testStopUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_STOP);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER, EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(0, targetUser,
+ USER_JOURNEY_USER_STOP);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER, EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_STOP, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testAbortStopUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_STOP);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER, EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+
+ mUserJourneyLogger.logUserJourneyFinishWithError(-1, targetUser,
+ USER_JOURNEY_USER_STOP, ERROR_CODE_ABORTED);
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ EVENT_STATE_CANCEL, ERROR_CODE_ABORTED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_STOP, -1, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_ABORTED, 1);
+ }
+
+ @Test
+ public void testIncompleteStopUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_STOP);
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ mUserJourneyLogger.finishAndClearIncompleteUserJourney(10, USER_JOURNEY_USER_STOP);
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ EVENT_STATE_ERROR,
+ ERROR_CODE_INCOMPLETE_OR_TIMEOUT, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_STOP, -1, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN,
+ -1, // information about user are incomplete
+ ERROR_CODE_INCOMPLETE_OR_TIMEOUT, 1);
+ }
+
+ @Test
+ public void testGrantAdminUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_GRANT_ADMIN);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_GRANT_ADMIN,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(0, targetUser,
+ USER_JOURNEY_GRANT_ADMIN);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_GRANT_ADMIN,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_GRANT_ADMIN, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testNullUserErrorGrantAdminUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+
+ UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_GRANT_ADMIN);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_GRANT_ADMIN,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ mUserJourneyLogger.logNullUserJourneyError(USER_JOURNEY_GRANT_ADMIN,
+ 0, 10, "", -1);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_GRANT_ADMIN,
+ EVENT_STATE_ERROR, ERROR_CODE_NULL_USER_INFO, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_GRANT_ADMIN, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNKNOWN,
+ -1, ERROR_CODE_NULL_USER_INFO, 1);
+ }
+
+ @Test
+ public void testRevokeAdminUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, UserJourneyLogger.USER_JOURNEY_REVOKE_ADMIN);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_REVOKE_ADMIN,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user", UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(0, targetUser,
+ UserJourneyLogger.USER_JOURNEY_REVOKE_ADMIN);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_REVOKE_ADMIN,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ UserJourneyLogger.USER_JOURNEY_REVOKE_ADMIN, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000400, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testSwitchFGUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(11, UserJourneyLogger.USER_JOURNEY_USER_SWITCH_FG);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserJourneyLogger.UserJourneySession session2 = mUserJourneyLogger
+ .logUserJourneyBegin(11, USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 2);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(11, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(10, targetUser,
+ USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 3);
+
+ report2.captureAndAssert(mUserJourneyLogger, session2.mSessionId,
+ USER_JOURNEY_USER_START, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+
+ mUserJourneyLogger.logUserSwitchJourneyFinish(10, targetUser);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 4);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ UserJourneyLogger.USER_JOURNEY_USER_SWITCH_FG, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 2);
+ }
+
+
+ @Test
+ public void testSwitchUIUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(11, UserJourneyLogger.USER_JOURNEY_USER_SWITCH_UI);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserJourneyLogger.UserJourneySession session2 = mUserJourneyLogger
+ .logUserJourneyBegin(11, USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 2);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ UserInfo targetUser = new UserInfo(11, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(10, targetUser,
+ USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 3);
+
+ report2.captureAndAssert(mUserJourneyLogger, session2.mSessionId,
+ USER_JOURNEY_USER_START, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+
+ mUserJourneyLogger.logUserSwitchJourneyFinish(10, targetUser);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_FINISH,
+ ERROR_CODE_UNSPECIFIED, 4);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ UserJourneyLogger.USER_JOURNEY_USER_SWITCH_UI, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 2);
+ }
+
+
+ @Test
+ public void testSwitchWithStopUIUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+
+ // BEGIN USER SWITCH
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(11, UserJourneyLogger.USER_JOURNEY_USER_SWITCH_UI);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ // BEGIN USER STOP
+ final UserJourneyLogger.UserJourneySession session2 = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_STOP);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 2);
+
+ // BEGIN USER START
+ UserJourneyLogger.UserJourneySession session3 = mUserJourneyLogger
+ .logUserJourneyBegin(11, USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session3.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 3);
+
+
+ // FINISH USER STOP
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(-1, targetUser,
+ USER_JOURNEY_USER_STOP);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 4);
+
+ report2.captureAndAssert(mUserJourneyLogger, session2.mSessionId,
+ USER_JOURNEY_USER_STOP, -1, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ FULL_USER_ADMIN_FLAG, ERROR_CODE_UNSPECIFIED, 1);
+
+ // FINISH USER START
+ final UserInfo targetUser2 = new UserInfo(11, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(10, targetUser2,
+ USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session3.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 5);
+
+ report2.captureAndAssert(mUserJourneyLogger, session3.mSessionId,
+ USER_JOURNEY_USER_START, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ FULL_USER_ADMIN_FLAG, ERROR_CODE_UNSPECIFIED, 2);
+
+
+ // FINISH USER SWITCH
+ mUserJourneyLogger.logUserSwitchJourneyFinish(10, targetUser2);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 6);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ UserJourneyLogger.USER_JOURNEY_USER_SWITCH_UI, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 3);
+ }
+
+ static class UserLifecycleJourneyReportedCaptor {
+ ArgumentCaptor<Long> mSessionId = ArgumentCaptor.forClass(Long.class);
+ ArgumentCaptor<Integer> mJourney = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mOriginalUserId = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mTargetUserId = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mUserType = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mUserFlags = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mErrorCode = ArgumentCaptor.forClass(Integer.class);
+
+ public void captureAndAssert(UserJourneyLogger mUserJourneyLogger,
+ long sessionId, int journey, int originalUserId,
+ int targetUserId, int userType, int userFlags, int errorCode, int times) {
+ verify(mUserJourneyLogger, times(times))
+ .writeUserLifecycleJourneyReported(mSessionId.capture(),
+ mJourney.capture(),
+ mOriginalUserId.capture(),
+ mTargetUserId.capture(),
+ mUserType.capture(),
+ mUserFlags.capture(),
+ mErrorCode.capture());
+
+ assertThat(mSessionId.getValue()).isEqualTo(sessionId);
+ assertThat(mJourney.getValue()).isEqualTo(journey);
+ assertThat(mOriginalUserId.getValue()).isEqualTo(originalUserId);
+ assertThat(mTargetUserId.getValue()).isEqualTo(targetUserId);
+ assertThat(mUserType.getValue()).isEqualTo(userType);
+ assertThat(mUserFlags.getValue()).isEqualTo(userFlags);
+ assertThat(mErrorCode.getValue()).isEqualTo(errorCode);
+ }
+
+
+ public void captureLogAndAssert(UserJourneyLogger mUserJourneyLogger,
+ UserJourneyLogger.UserJourneySession session, int journey, int originalUserId,
+ int targetUserId, int userType, int userFlags, int errorCode) {
+ mUserJourneyLogger.logUserLifecycleJourneyReported(session, journey, originalUserId,
+ targetUserId, userType, userFlags, errorCode);
+
+ captureAndAssert(mUserJourneyLogger, session.mSessionId, journey, originalUserId,
+ targetUserId, userType, userFlags, errorCode, 1);
+ }
+ }
+
+
+ static class UserLifecycleEventOccurredCaptor {
+ ArgumentCaptor<Long> mSessionId = ArgumentCaptor.forClass(Long.class);
+ ArgumentCaptor<Integer> mTargetUserId = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mEvent = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mStste = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mErrorCode = ArgumentCaptor.forClass(Integer.class);
+
+
+ public void captureAndAssert(UserJourneyLogger mUserJourneyLogger,
+ long sessionId, int targetUserId, int event, int state, int errorCode, int times) {
+ verify(mUserJourneyLogger, times(times))
+ .writeUserLifecycleEventOccurred(mSessionId.capture(),
+ mTargetUserId.capture(),
+ mEvent.capture(),
+ mStste.capture(),
+ mErrorCode.capture());
+
+ assertThat(mSessionId.getValue()).isEqualTo(sessionId);
+ assertThat(mTargetUserId.getValue()).isEqualTo(targetUserId);
+ assertThat(mEvent.getValue()).isEqualTo(event);
+ assertThat(mStste.getValue()).isEqualTo(state);
+ assertThat(mErrorCode.getValue()).isEqualTo(errorCode);
+ }
+
+
+ public void captureLogAndAssert(UserJourneyLogger mUserJourneyLogger,
+ UserJourneyLogger.UserJourneySession session, int targetUserId, int event,
+ int state, int errorCode) {
+ mUserJourneyLogger.logUserLifecycleEventOccurred(session, targetUserId, event,
+ state, errorCode);
+
+ captureAndAssert(mUserJourneyLogger, session.mSessionId, targetUserId, event,
+ state, errorCode, 1);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 52bf244e99fb..ae3ceb1203f8 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_ERRORED;
+import static android.os.PowerManager.USER_ACTIVITY_EVENT_BUTTON;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
@@ -41,6 +42,7 @@ import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -112,6 +114,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -2468,4 +2471,18 @@ public class PowerManagerServiceTest {
verify(mNotifierMock).onWakeLockReleased(anyInt(), eq(tag), eq(packageName), anyInt(),
anyInt(), any(), any(), same(callback2));
}
+
+ @Test
+ public void testUserActivity_futureEventsAreIgnored() {
+ createService();
+ startSystem();
+ // Starting the system triggers a user activity event, so clear that before calling
+ // userActivity() directly.
+ clearInvocations(mNotifierMock);
+ final long eventTime = mClock.now() + Duration.ofHours(10).toMillis();
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, eventTime,
+ USER_ACTIVITY_EVENT_BUTTON, /* flags= */ 0);
+ verify(mNotifierMock, never()).onUserActivity(anyInt(), anyInt(), anyInt());
+ }
+
}
diff --git a/services/tests/servicestests/utils/com/android/server/testutils/OWNERS b/services/tests/servicestests/utils/com/android/server/testutils/OWNERS
new file mode 100644
index 000000000000..bdacf7f37d3f
--- /dev/null
+++ b/services/tests/servicestests/utils/com/android/server/testutils/OWNERS
@@ -0,0 +1 @@
+per-file *Transaction.java = file:/services/core/java/com/android/server/wm/OWNERS \ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java
index 31546e85f8a4..34e8ff2ec5c4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm;
+package com.android.server.testutils;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -30,6 +30,8 @@ import android.view.InputWindowHandle;
import android.view.Surface;
import android.view.SurfaceControl;
+import com.android.server.testutils.StubTransaction;
+
import java.util.HashSet;
import java.util.concurrent.Executor;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index 397e3c1f55a2..539f329cae98 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -36,6 +36,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -47,7 +48,6 @@ import android.util.Pair;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.UiServiceTestCase;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -67,7 +67,7 @@ import java.util.Set;
public class PermissionHelperTest extends UiServiceTestCase {
@Mock
- private PermissionManagerServiceInternal mPmi;
+ private Context mContext;
@Mock
private IPackageManager mPackageManager;
@Mock
@@ -80,7 +80,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager);
+ mPermissionHelper = new PermissionHelper(mContext, mPackageManager, mPermManager);
PackageInfo testPkgInfo = new PackageInfo();
testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.POST_NOTIFICATIONS };
when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
@@ -89,12 +89,12 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Test
public void testHasPermission() throws Exception {
- when(mPmi.checkUidPermission(anyInt(), anyString()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
assertThat(mPermissionHelper.hasPermission(1)).isTrue();
- when(mPmi.checkUidPermission(anyInt(), anyString()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_DENIED);
assertThat(mPermissionHelper.hasPermission(1)).isFalse();
@@ -241,7 +241,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Test
public void testSetNotificationPermission_grantUserSet() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_DENIED);
mPermissionHelper.setNotificationPermission("pkg", 10, true, true);
@@ -255,7 +255,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Test
public void testSetNotificationPermission_pkgPerm_grantedByDefaultPermSet_allUserSet()
throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_DENIED);
when(mPermManager.getPermissionFlags(anyString(),
eq(Manifest.permission.POST_NOTIFICATIONS),
@@ -273,7 +273,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Test
public void testSetNotificationPermission_revokeUserSet() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
mPermissionHelper.setNotificationPermission("pkg", 10, false, true);
@@ -287,7 +287,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Test
public void testSetNotificationPermission_grantNotUserSet() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_DENIED);
mPermissionHelper.setNotificationPermission("pkg", 10, true, false);
@@ -300,7 +300,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Test
public void testSetNotificationPermission_revokeNotUserSet() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
@@ -340,7 +340,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Test
public void testSetNotificationPermission_alreadyGrantedNotRegranted() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
mPermissionHelper.setNotificationPermission("pkg", 10, true, false);
@@ -350,7 +350,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Test
public void testSetNotificationPermission_alreadyRevokedNotRerevoked() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_DENIED);
mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
@@ -360,16 +360,19 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Test
public void testSetNotificationPermission_doesntRequestNotChanged() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ int testUid = -1;
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
+ when(mPackageManager.getPackageUid(anyString(), anyInt(), anyInt()))
+ .thenReturn(testUid);
PackageInfo testPkgInfo = new PackageInfo();
testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.RECORD_AUDIO };
when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
.thenReturn(testPkgInfo);
mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
- verify(mPmi, never()).checkPermission(
- eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10));
+ verify(mContext, never()).checkPermission(
+ eq(Manifest.permission.POST_NOTIFICATIONS), eq(-1), eq(testUid));
verify(mPermManager, never()).revokeRuntimePermission(
eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
}
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/DeviceStateHandlerTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/DeviceStateHandlerTest.java
new file mode 100644
index 000000000000..089bd454bfb8
--- /dev/null
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/DeviceStateHandlerTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger;
+
+import static android.os.PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED;
+import static android.os.PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED;
+import static android.os.PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY;
+
+import static com.android.server.soundtrigger.DeviceStateHandler.SoundTriggerDeviceState;
+import static com.android.server.soundtrigger.DeviceStateHandler.SoundTriggerDeviceState.*;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.SystemClock;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.utils.EventLogger;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public final class DeviceStateHandlerTest {
+ private final long CONFIRM_NO_EVENT_WAIT_MS = 1000;
+ // A wait substantially less than the duration we delay phone notifications by
+ private final long PHONE_DELAY_BRIEF_WAIT_MS =
+ DeviceStateHandler.CALL_INACTIVE_MSG_DELAY_MS / 4;
+
+ private DeviceStateHandler mHandler;
+ private DeviceStateHandler.DeviceStateListener mDeviceStateCallback;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private SoundTriggerDeviceState mState;
+
+ @GuardedBy("mLock")
+ private CountDownLatch mLatch;
+
+ private EventLogger mEventLogger;
+
+ @Before
+ public void setup() {
+ // Reset the state prior to each test
+ mEventLogger = new EventLogger(256, "test logger");
+ synchronized (mLock) {
+ mLatch = new CountDownLatch(1);
+ }
+ mDeviceStateCallback =
+ (SoundTriggerDeviceState state) -> {
+ synchronized (mLock) {
+ mState = state;
+ mLatch.countDown();
+ }
+ };
+ mHandler = new DeviceStateHandler(Runnable::run, mEventLogger);
+ mHandler.onPhoneCallStateChanged(false);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ mHandler.registerListener(mDeviceStateCallback);
+ try {
+ waitAndAssertState(ENABLE);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void waitAndAssertState(SoundTriggerDeviceState state) throws InterruptedException {
+ CountDownLatch latch;
+ synchronized (mLock) {
+ latch = mLatch;
+ }
+ latch.await();
+ synchronized (mLock) {
+ assertThat(mState).isEqualTo(state);
+ mLatch = new CountDownLatch(1);
+ }
+ }
+
+ private void waitToConfirmNoEventReceived() throws InterruptedException {
+ CountDownLatch latch;
+ synchronized (mLock) {
+ latch = mLatch;
+ }
+ // Check that we time out
+ assertThat(latch.await(CONFIRM_NO_EVENT_WAIT_MS, TimeUnit.MILLISECONDS)).isFalse();
+ }
+
+ @Test
+ public void onPowerModeChangedCritical_receiveStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ waitAndAssertState(ENABLE);
+ }
+
+ @Test
+ public void onPowerModeChangedDisabled_receiveStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ waitAndAssertState(ENABLE);
+ }
+
+ @Test
+ public void onPowerModeChangedMultiple_receiveStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitAndAssertState(DISABLE);
+ }
+
+ @Test
+ public void onPowerModeSameState_noStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitToConfirmNoEventReceived();
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitToConfirmNoEventReceived();
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ waitAndAssertState(ENABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ waitToConfirmNoEventReceived();
+ }
+
+ @Test
+ public void onPhoneCall_receiveStateChange() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPhoneCallStateChanged(false);
+ waitAndAssertState(ENABLE);
+ }
+
+ @Test
+ public void onPhoneCall_receiveStateChangeIsDelayed() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ long beforeTime = SystemClock.uptimeMillis();
+ mHandler.onPhoneCallStateChanged(false);
+ waitAndAssertState(ENABLE);
+ long afterTime = SystemClock.uptimeMillis();
+ assertThat(afterTime - beforeTime).isAtLeast(DeviceStateHandler.CALL_INACTIVE_MSG_DELAY_MS);
+ }
+
+ @Test
+ public void onPhoneCallEnterExitEnter_receiveNoStateChange() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPhoneCallStateChanged(false);
+ SystemClock.sleep(PHONE_DELAY_BRIEF_WAIT_MS);
+ mHandler.onPhoneCallStateChanged(true);
+ waitToConfirmNoEventReceived();
+ }
+
+ @Test
+ public void onBatteryCallbackDuringPhoneWait_receiveStateChangeDelayed() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPhoneCallStateChanged(false);
+ SystemClock.sleep(PHONE_DELAY_BRIEF_WAIT_MS);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ // Ensure we don't get an ENABLE event after
+ waitToConfirmNoEventReceived();
+ }
+
+ @Test
+ public void onBatteryChangeWhenInPhoneCall_receiveNoStateChange() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ waitToConfirmNoEventReceived();
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitToConfirmNoEventReceived();
+ }
+
+ @Test
+ public void whenBatteryCriticalChangeDuringCallAfterPhoneCall_receiveCriticalStateChange()
+ throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitToConfirmNoEventReceived();
+ mHandler.onPhoneCallStateChanged(false);
+ waitAndAssertState(CRITICAL);
+ }
+
+ @Test
+ public void whenBatteryDisableDuringCallAfterPhoneCallBatteryEnable_receiveStateChange()
+ throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitToConfirmNoEventReceived();
+ mHandler.onPhoneCallStateChanged(false);
+ waitToConfirmNoEventReceived();
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ }
+
+ @Test
+ public void whenPhoneCallDuringBatteryDisable_receiveNoStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitAndAssertState(DISABLE);
+ mHandler.onPhoneCallStateChanged(true);
+ waitToConfirmNoEventReceived();
+ mHandler.onPhoneCallStateChanged(false);
+ waitToConfirmNoEventReceived();
+ }
+
+ @Test
+ public void whenPhoneCallDuringBatteryCritical_receiveStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPhoneCallStateChanged(false);
+ waitAndAssertState(CRITICAL);
+ }
+
+ // This test could be flaky, but we want to verify that we only delay notification if
+ // we are exiting a call, NOT if we are entering a call.
+ @FlakyTest
+ @Test
+ public void whenPhoneCallReceived_receiveStateChangeFast() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ CountDownLatch latch;
+ synchronized (mLock) {
+ latch = mLatch;
+ }
+ assertThat(latch.await(PHONE_DELAY_BRIEF_WAIT_MS, TimeUnit.MILLISECONDS)).isTrue();
+ synchronized (mLock) {
+ assertThat(mState).isEqualTo(DISABLE);
+ }
+ }
+}
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
index 2d0755d00ba8..3ac9a2758e08 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
@@ -16,6 +16,8 @@
package com.android.server.soundtrigger_middleware;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -34,12 +36,12 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.HwParcel;
import android.os.IBinder;
import android.os.IHwBinder;
@@ -617,13 +619,16 @@ public class SoundHw2CompatTest {
final int handle = 85;
final int status =
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT;
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
hwCallback.recognitionCallback(TestUtil.createRecognitionEvent_2_0(handle, status), 99);
mCanonical.flushCallbacks();
verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.ABORTED,
+ RecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent,
+ RecognitionStatus.ABORTED,
false);
}
@@ -631,14 +636,16 @@ public class SoundHw2CompatTest {
final int handle = 92;
final int status =
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS;
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
hwCallback.phraseRecognitionCallback(
TestUtil.createPhraseRecognitionEvent_2_0(handle, status), 99);
mCanonical.flushCallbacks();
verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+ PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent,
RecognitionStatus.SUCCESS, false);
}
verifyNoMoreInteractions(canonicalCallback);
@@ -652,28 +659,34 @@ public class SoundHw2CompatTest {
final int handle = 85;
final int status =
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT;
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status),
99);
mCanonical.flushCallbacks();
verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.ABORTED,
+ RecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent,
+ RecognitionStatus.ABORTED,
false);
}
{
final int handle = 87;
final int status = 3; // FORCED;
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status),
99);
mCanonical.flushCallbacks();
verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.FORCED,
+ RecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent,
+ RecognitionStatus.FORCED,
true);
}
@@ -681,28 +694,32 @@ public class SoundHw2CompatTest {
final int handle = 92;
final int status =
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS;
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
hwCallback.phraseRecognitionCallback_2_1(
TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99);
mCanonical.flushCallbacks();
verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+ PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent,
RecognitionStatus.SUCCESS, false);
}
{
final int handle = 102;
final int status = 3; // FORCED;
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
hwCallback.phraseRecognitionCallback_2_1(
TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99);
mCanonical.flushCallbacks();
verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+ PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent,
RecognitionStatus.FORCED, true);
}
verifyNoMoreInteractions(canonicalCallback);
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
index 61989252d04d..9a59ede20e23 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
@@ -30,8 +30,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import androidx.annotation.NonNull;
@@ -68,13 +68,14 @@ public class SoundTriggerHalConcurrentCaptureHandlerTest {
mNotifier.setActive(true);
verify(mUnderlying).stopRecognition(handle);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
Thread.sleep(50);
verify(callback).recognitionCallback(eq(handle), eventCaptor.capture());
- RecognitionEvent event = eventCaptor.getValue();
- assertEquals(event.status, RecognitionStatus.ABORTED);
- assertFalse(event.recognitionStillActive);
+ RecognitionEventSys event = eventCaptor.getValue();
+ assertEquals(event.halEventReceivedMillis, -1);
+ assertEquals(event.recognitionEvent.status, RecognitionStatus.ABORTED);
+ assertFalse(event.recognitionEvent.recognitionStillActive);
verifyZeroInteractions(mGlobalCallback);
clearInvocations(callback, mUnderlying);
@@ -116,8 +117,11 @@ public class SoundTriggerHalConcurrentCaptureHandlerTest {
mNotifier.setActive(true);
verify(mUnderlying, times(1)).stopRecognition(handle);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
mHandler.stopRecognition(handle);
- verify(callback, times(1)).recognitionCallback(eq(handle), any());
+ verify(callback).recognitionCallback(eq(handle), eventCaptor.capture());
+ assertEquals(eventCaptor.getValue().halEventReceivedMillis, -1);
}
@Test(timeout = 200)
@@ -133,19 +137,21 @@ public class SoundTriggerHalConcurrentCaptureHandlerTest {
verify(mUnderlying).startRecognition(eq(handle), eq(101), eq(102), any());
doAnswer(invocation -> {
- RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.ABORTED,
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+ RecognitionStatus.ABORTED,
false);
+ recognitionEventSys.halEventReceivedMillis = 12345;
// Call the callback from a different thread to detect deadlocks by preventing recursive
// locking from working.
- runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+ runOnSeparateThread(
+ () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
return null;
}).when(mUnderlying).stopRecognition(handle);
mHandler.stopRecognition(handle);
verify(mUnderlying, times(1)).stopRecognition(handle);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
- verify(callback, atMost(1)).recognitionCallback(eq(handle), eventCaptor.capture());
+ verify(callback, atMost(1)).recognitionCallback(eq(handle), any(RecognitionEventSys.class));
}
@Test(timeout = 200)
@@ -162,11 +168,15 @@ public class SoundTriggerHalConcurrentCaptureHandlerTest {
doAnswer(invocation -> {
// The stop request causes a callback to be flushed.
- RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.FORCED,
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+ RecognitionStatus.FORCED,
true);
+ recognitionEventSys.halEventReceivedMillis = 12345;
// Call the callback from a different thread to detect deadlocks by preventing recursive
// locking from working.
- runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+ runOnSeparateThread(
+ () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
// While the HAL is processing the stop request, capture state becomes active.
new Thread(() -> mNotifier.setActive(true)).start();
Thread.sleep(50);
@@ -194,11 +204,15 @@ public class SoundTriggerHalConcurrentCaptureHandlerTest {
doAnswer(invocation -> {
// The stop request causes a callback to be flushed.
- RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.FORCED,
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+ RecognitionStatus.FORCED,
true);
+ recognitionEventSys.halEventReceivedMillis = 12345;
// Call the callback from a different thread to detect deadlocks by preventing recursive
// locking from working.
- runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+ runOnSeparateThread(
+ () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
// While the HAL is processing the stop request, client requests stop.
new Thread(() -> mHandler.stopRecognition(handle)).start();
Thread.sleep(50);
@@ -223,23 +237,22 @@ public class SoundTriggerHalConcurrentCaptureHandlerTest {
verify(mUnderlying).startRecognition(eq(handle), eq(101), eq(102), any());
doAnswer(invocation -> {
- RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.SUCCESS,
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+ RecognitionStatus.SUCCESS,
false);
+ recognitionEventSys.halEventReceivedMillis = 12345;
// Call the callback from a different thread to detect deadlocks by preventing recursive
// locking from working.
- runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+ runOnSeparateThread(
+ () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
return null;
}).when(mUnderlying).stopRecognition(handle);
mNotifier.setActive(true);
verify(mUnderlying, times(1)).stopRecognition(handle);
Thread.sleep(50);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
- verify(callback, atMost(2)).recognitionCallback(eq(handle), eventCaptor.capture());
- RecognitionEvent lastEvent = eventCaptor.getValue();
- assertEquals(lastEvent.status, RecognitionStatus.ABORTED);
- assertFalse(lastEvent.recognitionStillActive);
+ verify(callback, atMost(2)).recognitionCallback(eq(handle), any());
}
@@ -256,11 +269,15 @@ public class SoundTriggerHalConcurrentCaptureHandlerTest {
verify(mUnderlying).startRecognition(eq(handle), eq(101), eq(102), any());
doAnswer(invocation -> {
- RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.FORCED,
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+ RecognitionStatus.FORCED,
true);
+ recognitionEventSys.halEventReceivedMillis = 12345;
// Call the callback from a different thread to detect deadlocks by preventing recursive
// locking from working.
- runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+ runOnSeparateThread(
+ () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
return null;
}).when(mUnderlying).stopRecognition(handle);
@@ -268,12 +285,7 @@ public class SoundTriggerHalConcurrentCaptureHandlerTest {
verify(mUnderlying, times(1)).stopRecognition(handle);
Thread.sleep(50);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
- verify(callback, atMost(2)).recognitionCallback(eq(handle), eventCaptor.capture());
- RecognitionEvent lastEvent = eventCaptor.getValue();
- assertEquals(lastEvent.status, RecognitionStatus.ABORTED);
- assertFalse(lastEvent.recognitionStillActive);
+ verify(callback, atMost(2)).recognitionCallback(eq(handle), any());
}
private static void runOnSeparateThread(Runnable runnable) {
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index 3bebc94fe0ed..5a2451f3b17e 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -30,18 +30,19 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.ElapsedRealtimeLong;
import android.media.soundtrigger.ModelParameter;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.RemoteException;
import android.util.Pair;
@@ -224,10 +225,12 @@ public class SoundTriggerMiddlewareImplTest {
// Stop the recognition.
stopRecognition(module, handle, hwHandle);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
- assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
+ RecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertEquals(-1, lastEvent.halEventReceivedMillis);
+ assertEquals(RecognitionStatus.ABORTED, lastEvent.recognitionEvent.status);
// Unload the model.
unloadModel(module, handle, hwHandle);
@@ -273,10 +276,12 @@ public class SoundTriggerMiddlewareImplTest {
// Stop the recognition.
stopRecognition(module, handle, hwHandle);
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
- assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
+ PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertEquals(-1, lastEvent.halEventReceivedMillis);
+ assertEquals(RecognitionStatus.ABORTED, lastEvent.phraseRecognitionEvent.common.status);
// Unload the model.
unloadModel(module, handle, hwHandle);
@@ -299,11 +304,11 @@ public class SoundTriggerMiddlewareImplTest {
{
// Signal a capture from the driver (with "still active").
- RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
- RecognitionStatus.SUCCESS, true);
+ RecognitionEventSys event = hwCallback.sendRecognitionEvent(hwHandle,
+ RecognitionStatus.SUCCESS, true, 12345);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
@@ -312,11 +317,11 @@ public class SoundTriggerMiddlewareImplTest {
{
// Signal a capture from the driver (without "still active").
- RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
- RecognitionStatus.SUCCESS, false);
+ RecognitionEventSys event = hwCallback.sendRecognitionEvent(hwHandle,
+ RecognitionStatus.SUCCESS, false, 12345);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
verify(callback, times(2)).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
@@ -343,11 +348,11 @@ public class SoundTriggerMiddlewareImplTest {
startRecognition(module, handle, hwHandle);
// Signal a capture from the driver.
- PhraseRecognitionEvent event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
- RecognitionStatus.SUCCESS, false);
+ PhraseRecognitionEventSys event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
+ RecognitionStatus.SUCCESS, false, 12345);
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
@@ -377,11 +382,11 @@ public class SoundTriggerMiddlewareImplTest {
verify(mHalDriver).forceRecognitionEvent(hwHandle);
// Signal a capture from the driver.
- RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
- RecognitionStatus.FORCED, true);
+ RecognitionEventSys event = hwCallback.sendRecognitionEvent(hwHandle,
+ RecognitionStatus.FORCED, true, 12345);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
@@ -445,11 +450,11 @@ public class SoundTriggerMiddlewareImplTest {
verify(mHalDriver).forceRecognitionEvent(hwHandle);
// Signal a capture from the driver.
- PhraseRecognitionEvent event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
- RecognitionStatus.FORCED, true);
+ PhraseRecognitionEventSys event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
+ RecognitionStatus.FORCED, true, 12345);
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
@@ -510,14 +515,16 @@ public class SoundTriggerMiddlewareImplTest {
startRecognition(module, handle, hwHandle);
// Abort.
- hwCallback.sendRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false);
+ hwCallback.sendRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false, 12345);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
- assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
+ RecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertEquals(12345, lastEvent.halEventReceivedMillis);
+ assertEquals(RecognitionStatus.ABORTED, lastEvent.recognitionEvent.status);
// Unload the model.
unloadModel(module, handle, hwHandle);
@@ -540,14 +547,16 @@ public class SoundTriggerMiddlewareImplTest {
startRecognition(module, handle, hwHandle);
// Abort.
- hwCallback.sendPhraseRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false);
+ hwCallback.sendPhraseRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false, 12345);
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
- assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
+ PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertEquals(12345, lastEvent.halEventReceivedMillis);
+ assertEquals(RecognitionStatus.ABORTED, lastEvent.phraseRecognitionEvent.common.status);
// Unload the model.
unloadModel(module, handle, hwHandle);
@@ -630,18 +639,24 @@ public class SoundTriggerMiddlewareImplTest {
mCallback = callback;
}
- private RecognitionEvent sendRecognitionEvent(int hwHandle, @RecognitionStatus int status,
- boolean recognitionStillActive) {
- RecognitionEvent event = TestUtil.createRecognitionEvent(status,
+ private RecognitionEventSys sendRecognitionEvent(int hwHandle,
+ @RecognitionStatus int status,
+ boolean recognitionStillActive, @ElapsedRealtimeLong long halEventReceivedMillis) {
+ RecognitionEventSys event = new RecognitionEventSys();
+ event.recognitionEvent = TestUtil.createRecognitionEvent(status,
recognitionStillActive);
+ event.halEventReceivedMillis = halEventReceivedMillis;
mCallback.recognitionCallback(hwHandle, event);
return event;
}
- private PhraseRecognitionEvent sendPhraseRecognitionEvent(int hwHandle,
- @RecognitionStatus int status, boolean recognitionStillActive) {
- PhraseRecognitionEvent event = TestUtil.createPhraseRecognitionEvent(status,
+ private PhraseRecognitionEventSys sendPhraseRecognitionEvent(int hwHandle,
+ @RecognitionStatus int status, boolean recognitionStillActive,
+ @ElapsedRealtimeLong long halEventReceivedMillis) {
+ PhraseRecognitionEventSys event = new PhraseRecognitionEventSys();
+ event.phraseRecognitionEvent = TestUtil.createPhraseRecognitionEvent(status,
recognitionStillActive);
+ event.halEventReceivedMillis = halEventReceivedMillis;
mCallback.phraseRecognitionCallback(hwHandle, event);
return event;
}
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
new file mode 100644
index 000000000000..cc357d76cb4a
--- /dev/null
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger_middleware;
+
+import static com.android.internal.util.LatencyTracker.ACTION_SHOW_VOICE_INTERACTION;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+
+import android.Manifest;
+import android.app.ActivityThread;
+import android.media.permission.Identity;
+import android.media.permission.IdentityContext;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseRecognitionExtra;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger_middleware.ISoundTriggerCallback;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.os.BatteryStatsInternal;
+import android.os.Process;
+import android.os.RemoteException;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.util.FakeLatencyTracker;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(JUnit4.class)
+public class SoundTriggerMiddlewareLoggingLatencyTest {
+
+ private FakeLatencyTracker mLatencyTracker;
+ @Mock
+ private BatteryStatsInternal mBatteryStatsInternal;
+ @Mock
+ private ISoundTriggerMiddlewareInternal mDelegateMiddleware;
+ @Mock
+ private ISoundTriggerCallback mISoundTriggerCallback;
+ private SoundTriggerMiddlewareLogging mSoundTriggerMiddlewareLogging;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(Manifest.permission.WRITE_DEVICE_CONFIG,
+ Manifest.permission.READ_DEVICE_CONFIG);
+
+ Identity identity = new Identity();
+ identity.uid = Process.myUid();
+ identity.pid = Process.myPid();
+ identity.packageName = ActivityThread.currentOpPackageName();
+ IdentityContext.create(identity);
+
+ mLatencyTracker = FakeLatencyTracker.create();
+ mLatencyTracker.forceEnabled(ACTION_SHOW_VOICE_INTERACTION, -1);
+ mSoundTriggerMiddlewareLogging = new SoundTriggerMiddlewareLogging(mLatencyTracker,
+ () -> mBatteryStatsInternal,
+ mDelegateMiddleware);
+ }
+
+ @After
+ public void tearDown() {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+ @Test
+ @FlakyTest(bugId = 275113847)
+ public void testSetUpAndTearDown() {
+ }
+
+ @Test
+ @FlakyTest(bugId = 275113847)
+ public void testOnPhraseRecognitionStartsLatencyTrackerWithSuccessfulPhraseIdTrigger()
+ throws RemoteException {
+ ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
+ ISoundTriggerCallback.class);
+ mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
+ verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
+
+ triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
+ RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
+
+ assertThat(mLatencyTracker.getActiveActionStartTime(
+ ACTION_SHOW_VOICE_INTERACTION)).isGreaterThan(-1);
+ }
+
+ @Test
+ @FlakyTest(bugId = 275113847)
+ public void testOnPhraseRecognitionRestartsActiveSession() throws RemoteException {
+ ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
+ ISoundTriggerCallback.class);
+ mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
+ verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
+
+ triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
+ RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
+ long firstTriggerSessionStartTime = mLatencyTracker.getActiveActionStartTime(
+ ACTION_SHOW_VOICE_INTERACTION);
+ triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
+ RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
+ assertThat(mLatencyTracker.getActiveActionStartTime(
+ ACTION_SHOW_VOICE_INTERACTION)).isGreaterThan(-1);
+ assertThat(mLatencyTracker.getActiveActionStartTime(
+ ACTION_SHOW_VOICE_INTERACTION)).isNotEqualTo(firstTriggerSessionStartTime);
+ }
+
+ @Test
+ @FlakyTest(bugId = 275113847)
+ public void testOnPhraseRecognitionNeverStartsLatencyTrackerWithNonSuccessEvent()
+ throws RemoteException {
+ ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
+ ISoundTriggerCallback.class);
+ mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
+ verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
+
+ triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
+ RecognitionStatus.ABORTED, 100 /* keyphraseId */);
+
+ assertThat(
+ mLatencyTracker.getActiveActionStartTime(ACTION_SHOW_VOICE_INTERACTION)).isEqualTo(
+ -1);
+ }
+
+ @Test
+ @FlakyTest(bugId = 275113847)
+ public void testOnPhraseRecognitionNeverStartsLatencyTrackerWithNoKeyphraseId()
+ throws RemoteException {
+ ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
+ ISoundTriggerCallback.class);
+ mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
+ verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
+
+ triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
+ RecognitionStatus.SUCCESS);
+
+ assertThat(
+ mLatencyTracker.getActiveActionStartTime(ACTION_SHOW_VOICE_INTERACTION)).isEqualTo(
+ -1);
+ }
+
+ private void triggerPhraseRecognitionEvent(ISoundTriggerCallback callback,
+ @RecognitionStatus int triggerEventStatus) throws RemoteException {
+ triggerPhraseRecognitionEvent(callback, triggerEventStatus, -1 /* keyphraseId */);
+ }
+
+ private void triggerPhraseRecognitionEvent(ISoundTriggerCallback callback,
+ @RecognitionStatus int triggerEventStatus, int keyphraseId) throws RemoteException {
+ // trigger a phrase recognition to start a latency tracker session
+ PhraseRecognitionEvent successEventWithKeyphraseId = new PhraseRecognitionEvent();
+ successEventWithKeyphraseId.common = new RecognitionEvent();
+ successEventWithKeyphraseId.common.status = triggerEventStatus;
+ if (keyphraseId > 0) {
+ PhraseRecognitionExtra recognitionExtra = new PhraseRecognitionExtra();
+ recognitionExtra.id = keyphraseId;
+ successEventWithKeyphraseId.phraseExtras =
+ new PhraseRecognitionExtra[]{recognitionExtra};
+ }
+ PhraseRecognitionEventSys phraseRecognitionEventSys = new PhraseRecognitionEventSys();
+ phraseRecognitionEventSys.phraseRecognitionEvent = successEventWithKeyphraseId;
+ phraseRecognitionEventSys.halEventReceivedMillis = 12345;
+ callback.onPhraseRecognition(0 /* modelHandle */, phraseRecognitionEventSys,
+ 0 /* captureSession */);
+ }
+
+}
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java
index eb117d128383..f92e0dbe94e0 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java
@@ -18,186 +18,27 @@ package com.android.server.soundtrigger_middleware;
import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.ServiceEvent;
import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent;
-import static com.android.internal.util.LatencyTracker.ACTION_SHOW_VOICE_INTERACTION;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.verify;
-
-import android.Manifest;
-import android.app.ActivityThread;
-import android.media.permission.Identity;
-import android.media.permission.IdentityContext;
-import android.media.soundtrigger.PhraseRecognitionEvent;
-import android.media.soundtrigger.PhraseRecognitionExtra;
-import android.media.soundtrigger.RecognitionEvent;
-import android.media.soundtrigger.RecognitionStatus;
-import android.media.soundtrigger_middleware.ISoundTriggerCallback;
-import android.media.soundtrigger_middleware.ISoundTriggerModule;
-import android.os.BatteryStatsInternal;
-import android.os.Process;
-import android.os.RemoteException;
-
-import androidx.test.filters.FlakyTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.internal.util.FakeLatencyTracker;
-
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Optional;
@RunWith(JUnit4.class)
public class SoundTriggerMiddlewareLoggingTest {
private static final ServiceEvent.Type SERVICE_TYPE = ServiceEvent.Type.ATTACH;
private static final SessionEvent.Type SESSION_TYPE = SessionEvent.Type.LOAD_MODEL;
- private FakeLatencyTracker mLatencyTracker;
- @Mock
- private BatteryStatsInternal mBatteryStatsInternal;
- @Mock
- private ISoundTriggerMiddlewareInternal mDelegateMiddleware;
- @Mock
- private ISoundTriggerCallback mISoundTriggerCallback;
- @Mock
- private ISoundTriggerModule mSoundTriggerModule;
- private SoundTriggerMiddlewareLogging mSoundTriggerMiddlewareLogging;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .adoptShellPermissionIdentity(Manifest.permission.WRITE_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG);
-
- Identity identity = new Identity();
- identity.uid = Process.myUid();
- identity.pid = Process.myPid();
- identity.packageName = ActivityThread.currentOpPackageName();
- IdentityContext.create(identity);
-
- mLatencyTracker = FakeLatencyTracker.create();
- mLatencyTracker.forceEnabled(ACTION_SHOW_VOICE_INTERACTION, -1);
- mSoundTriggerMiddlewareLogging = new SoundTriggerMiddlewareLogging(mLatencyTracker,
- () -> mBatteryStatsInternal,
- mDelegateMiddleware);
- }
-
- @After
- public void tearDown() {
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .dropShellPermissionIdentity();
- }
-
- @Test
- @FlakyTest(bugId = 275113847)
- public void testSetUpAndTearDown() {
- }
-
- @Test
- @FlakyTest(bugId = 275113847)
- public void testOnPhraseRecognitionStartsLatencyTrackerWithSuccessfulPhraseIdTrigger()
- throws RemoteException {
- ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
- ISoundTriggerCallback.class);
- mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
- verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
-
- triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
- RecognitionStatus.SUCCESS, Optional.of(100) /* keyphraseId */);
-
- assertThat(mLatencyTracker.getActiveActionStartTime(
- ACTION_SHOW_VOICE_INTERACTION)).isGreaterThan(-1);
- }
-
- @Test
- @FlakyTest(bugId = 275113847)
- public void testOnPhraseRecognitionRestartsActiveSession() throws RemoteException {
- ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
- ISoundTriggerCallback.class);
- mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
- verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
-
- triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
- RecognitionStatus.SUCCESS, Optional.of(100) /* keyphraseId */);
- long firstTriggerSessionStartTime = mLatencyTracker.getActiveActionStartTime(
- ACTION_SHOW_VOICE_INTERACTION);
- triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
- RecognitionStatus.SUCCESS, Optional.of(100) /* keyphraseId */);
- assertThat(mLatencyTracker.getActiveActionStartTime(
- ACTION_SHOW_VOICE_INTERACTION)).isGreaterThan(-1);
- assertThat(mLatencyTracker.getActiveActionStartTime(
- ACTION_SHOW_VOICE_INTERACTION)).isNotEqualTo(firstTriggerSessionStartTime);
- }
-
- @Test
- @FlakyTest(bugId = 275113847)
- public void testOnPhraseRecognitionNeverStartsLatencyTrackerWithNonSuccessEvent()
- throws RemoteException {
- ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
- ISoundTriggerCallback.class);
- mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
- verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
-
- triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
- RecognitionStatus.ABORTED, Optional.of(100) /* keyphraseId */);
-
- assertThat(
- mLatencyTracker.getActiveActionStartTime(ACTION_SHOW_VOICE_INTERACTION)).isEqualTo(
- -1);
- }
-
- @Test
- @FlakyTest(bugId = 275113847)
- public void testOnPhraseRecognitionNeverStartsLatencyTrackerWithNoKeyphraseId()
- throws RemoteException {
- ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
- ISoundTriggerCallback.class);
- mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
- verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
-
- triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
- RecognitionStatus.SUCCESS, Optional.empty() /* keyphraseId */);
-
- assertThat(
- mLatencyTracker.getActiveActionStartTime(ACTION_SHOW_VOICE_INTERACTION)).isEqualTo(
- -1);
- }
-
- private void triggerPhraseRecognitionEvent(ISoundTriggerCallback callback,
- @RecognitionStatus int triggerEventStatus, Optional<Integer> optionalKeyphraseId)
- throws RemoteException {
- // trigger a phrase recognition to start a latency tracker session
- PhraseRecognitionEvent successEventWithKeyphraseId = new PhraseRecognitionEvent();
- successEventWithKeyphraseId.common = new RecognitionEvent();
- successEventWithKeyphraseId.common.status = triggerEventStatus;
- if (optionalKeyphraseId.isPresent()) {
- PhraseRecognitionExtra recognitionExtra = new PhraseRecognitionExtra();
- recognitionExtra.id = optionalKeyphraseId.get();
- successEventWithKeyphraseId.phraseExtras =
- new PhraseRecognitionExtra[]{recognitionExtra};
- }
- callback.onPhraseRecognition(0 /* modelHandle */, successEventWithKeyphraseId,
- 0 /* captureSession */);
- }
-
@Test
public void serviceEventException_getStringContainsInfo() {
String packageName = "com.android.test";
Exception exception = new Exception("test");
Object param1 = new Object();
Object param2 = new Object();
- final var event = ServiceEvent.createForException(
- SERVICE_TYPE, packageName, exception, param1, param2);
+ final var event =
+ ServiceEvent.createForException(
+ SERVICE_TYPE, packageName, exception, param1, param2);
final var stringRep = event.eventToString();
assertThat(stringRep).contains(SERVICE_TYPE.name());
assertThat(stringRep).contains(packageName);
@@ -211,8 +52,7 @@ public class SoundTriggerMiddlewareLoggingTest {
public void serviceEventExceptionNoArgs_getStringContainsInfo() {
String packageName = "com.android.test";
Exception exception = new Exception("test");
- final var event = ServiceEvent.createForException(
- SERVICE_TYPE, packageName, exception);
+ final var event = ServiceEvent.createForException(SERVICE_TYPE, packageName, exception);
final var stringRep = event.eventToString();
assertThat(stringRep).contains(SERVICE_TYPE.name());
assertThat(stringRep).contains(packageName);
@@ -226,8 +66,8 @@ public class SoundTriggerMiddlewareLoggingTest {
Object param1 = new Object();
Object param2 = new Object();
Object retValue = new Object();
- final var event = ServiceEvent.createForReturn(
- SERVICE_TYPE, packageName, retValue, param1, param2);
+ final var event =
+ ServiceEvent.createForReturn(SERVICE_TYPE, packageName, retValue, param1, param2);
final var stringRep = event.eventToString();
assertThat(stringRep).contains(SERVICE_TYPE.name());
assertThat(stringRep).contains(packageName);
@@ -241,8 +81,7 @@ public class SoundTriggerMiddlewareLoggingTest {
public void serviceEventReturnNoArgs_getStringContainsInfo() {
String packageName = "com.android.test";
Object retValue = new Object();
- final var event = ServiceEvent.createForReturn(
- SERVICE_TYPE, packageName, retValue);
+ final var event = ServiceEvent.createForReturn(SERVICE_TYPE, packageName, retValue);
final var stringRep = event.eventToString();
assertThat(stringRep).contains(SERVICE_TYPE.name());
assertThat(stringRep).contains(packageName);
@@ -255,8 +94,7 @@ public class SoundTriggerMiddlewareLoggingTest {
Object param1 = new Object();
Object param2 = new Object();
Exception exception = new Exception("test");
- final var event = SessionEvent.createForException(
- SESSION_TYPE, exception, param1, param2);
+ final var event = SessionEvent.createForException(SESSION_TYPE, exception, param1, param2);
final var stringRep = event.eventToString();
assertThat(stringRep).contains(SESSION_TYPE.name());
assertThat(stringRep).contains(exception.toString());
@@ -268,8 +106,7 @@ public class SoundTriggerMiddlewareLoggingTest {
@Test
public void sessionEventExceptionNoArgs_getStringContainsInfo() {
Exception exception = new Exception("test");
- final var event = SessionEvent.createForException(
- SESSION_TYPE, exception);
+ final var event = SessionEvent.createForException(SESSION_TYPE, exception);
final var stringRep = event.eventToString();
assertThat(stringRep).contains(SESSION_TYPE.name());
assertThat(stringRep).contains(exception.toString());
@@ -281,8 +118,7 @@ public class SoundTriggerMiddlewareLoggingTest {
Object param1 = new Object();
Object param2 = new Object();
Object retValue = new Object();
- final var event = SessionEvent.createForReturn(
- SESSION_TYPE, retValue, param1, param2);
+ final var event = SessionEvent.createForReturn(SESSION_TYPE, retValue, param1, param2);
final var stringRep = event.eventToString();
assertThat(stringRep).contains(SESSION_TYPE.name());
assertThat(stringRep).contains(retValue.toString());
@@ -294,8 +130,7 @@ public class SoundTriggerMiddlewareLoggingTest {
@Test
public void sessionEventReturnNoArgs_getStringContainsInfo() {
Object retValue = new Object();
- final var event = SessionEvent.createForReturn(
- SESSION_TYPE, retValue);
+ final var event = SessionEvent.createForReturn(SESSION_TYPE, retValue);
final var stringRep = event.eventToString();
assertThat(stringRep).contains(SESSION_TYPE.name());
assertThat(stringRep).contains(retValue.toString());
@@ -306,8 +141,7 @@ public class SoundTriggerMiddlewareLoggingTest {
public void sessionEventVoid_getStringContainsInfo() {
Object param1 = new Object();
Object param2 = new Object();
- final var event = SessionEvent.createForVoid(
- SESSION_TYPE, param1, param2);
+ final var event = SessionEvent.createForVoid(SESSION_TYPE, param1, param2);
final var stringRep = event.eventToString();
assertThat(stringRep).contains(SESSION_TYPE.name());
assertThat(stringRep).contains(param1.toString());
@@ -317,8 +151,7 @@ public class SoundTriggerMiddlewareLoggingTest {
@Test
public void sessionEventVoidNoArgs_getStringContainsInfo() {
- final var event = SessionEvent.createForVoid(
- SESSION_TYPE);
+ final var event = SessionEvent.createForVoid(SESSION_TYPE);
final var stringRep = event.eventToString();
assertThat(stringRep).contains(SESSION_TYPE.name());
assertThat(stringRep).ignoringCase().doesNotContain("error");
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 5282585e9757..f235d153c658 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -36,6 +36,7 @@ import android.view.SurfaceControl;
import android.view.SurfaceSession;
import com.android.server.wm.SurfaceAnimator.AnimationType;
+import com.android.server.testutils.StubTransaction;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index d400a4c9daca..d2494ff3fc9a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -37,6 +37,8 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
+import com.android.server.testutils.StubTransaction;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
index e30206ee0a64..c8fc6b892bc8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
@@ -30,6 +30,8 @@ import android.window.SurfaceSyncGroup;
import androidx.test.filters.SmallTest;
+import com.android.server.testutils.StubTransaction;
+
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java
index ddd630ee8635..a3a36841d807 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java
@@ -42,6 +42,7 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
+import com.android.server.testutils.StubTransaction;
import com.android.server.testutils.TestHandler;
import org.junit.Before;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 013c6d50d4e7..7edfd9a3ecb3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -88,6 +88,7 @@ import com.android.server.pm.UserManagerService;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.testutils.StubTransaction;
import com.android.server.uri.UriGrantsManagerInternal;
import org.junit.rules.TestRule;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
index e2f1334c7f8c..608d7c9707f9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
@@ -38,6 +38,8 @@ import android.view.animation.ClipRectAnimation;
import androidx.test.filters.SmallTest;
+import com.android.server.testutils.StubTransaction;
+
import org.junit.Test;
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index ad606cb90841..2d8ddfa47300 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -1443,10 +1443,8 @@ public class WindowContainerTests extends WindowTestsBase {
final InsetsFrameProvider provider2 =
new InsetsFrameProvider(null, 2, WindowInsets.Type.systemOverlays())
.setArbitraryRectangle(genericOverlayInsetsRect2);
- final int sourceId1 = InsetsSource.createId(
- provider1.getOwner(), provider1.getIndex(), provider1.getType());
- final int sourceId2 = InsetsSource.createId(
- provider2.getOwner(), provider2.getIndex(), provider2.getType());
+ final int sourceId1 = provider1.getId();
+ final int sourceId2 = provider2.getId();
rootTask.addLocalInsetsFrameProvider(provider1);
container.addLocalInsetsFrameProvider(provider2);
@@ -1504,10 +1502,8 @@ public class WindowContainerTests extends WindowTestsBase {
final InsetsFrameProvider provider2 =
new InsetsFrameProvider(null, 1, WindowInsets.Type.systemOverlays())
.setArbitraryRectangle(genericOverlayInsetsRect2);
- final int sourceId1 = InsetsSource.createId(
- provider1.getOwner(), provider1.getIndex(), provider1.getType());
- final int sourceId2 = InsetsSource.createId(
- provider2.getOwner(), provider2.getIndex(), provider2.getType());
+ final int sourceId1 = provider1.getId();
+ final int sourceId2 = provider2.getId();
rootTask.addLocalInsetsFrameProvider(provider1);
activity0.forAllWindows(window -> {
@@ -1566,10 +1562,8 @@ public class WindowContainerTests extends WindowTestsBase {
final InsetsFrameProvider provider2 =
new InsetsFrameProvider(null, 2, WindowInsets.Type.systemOverlays())
.setArbitraryRectangle(navigationBarInsetsRect2);
- final int sourceId1 = InsetsSource.createId(
- provider1.getOwner(), provider1.getIndex(), provider1.getType());
- final int sourceId2 = InsetsSource.createId(
- provider2.getOwner(), provider2.getIndex(), provider2.getType());
+ final int sourceId1 = provider1.getId();
+ final int sourceId2 = provider2.getId();
rootTask.addLocalInsetsFrameProvider(provider1);
container.addLocalInsetsFrameProvider(provider2);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
index 2ae117214dd3..849072e133ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
@@ -28,6 +28,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.server.testutils.StubTransaction;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 460a603d51a2..ee1afcf318fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -110,6 +110,8 @@ import android.window.TaskFragmentOrganizer;
import androidx.test.filters.SmallTest;
+import com.android.server.testutils.StubTransaction;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index a63807d23a14..a4cad5e24dc1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -359,9 +359,12 @@ class WindowTestsBase extends SystemServiceTestsBase {
new InsetsFrameProvider(owner, 0, WindowInsets.Type.tappableElement()),
new InsetsFrameProvider(owner, 0, WindowInsets.Type.mandatorySystemGestures())
};
- for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
- mNavBarWindow.mAttrs.paramsForRotation[rot] =
- getNavBarLayoutParamsForRotation(rot, owner);
+ // If the navigation bar cannot move then it is always at the bottom.
+ if (mDisplayContent.getDisplayPolicy().navigationBarCanMove()) {
+ for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+ mNavBarWindow.mAttrs.paramsForRotation[rot] =
+ getNavBarLayoutParamsForRotation(rot, owner);
+ }
}
}
if (addAll || ArrayUtils.contains(requestedWindows, W_DOCK_DIVIDER)) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index a98429ad4902..ef1359449b9b 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2539,10 +2539,20 @@ public class UsageStatsService extends SystemService implements
}
@Override
- public void reportChooserSelection(String packageName, int userId, String contentType,
- String[] annotations, String action) {
+ public void reportChooserSelection(@NonNull String packageName, int userId,
+ @NonNull String contentType, String[] annotations, @NonNull String action) {
if (packageName == null) {
- Slog.w(TAG, "Event report user selecting a null package");
+ throw new IllegalArgumentException("Package selection must not be null.");
+ }
+ if (contentType == null) {
+ throw new IllegalArgumentException("Content type for selection must not be null.");
+ }
+ if (action == null) {
+ throw new IllegalArgumentException("Selection action must not be null.");
+ }
+ // Verify if this package exists before reporting an event for it.
+ if (mPackageManagerInternal.getPackageUid(packageName, 0, userId) < 0) {
+ Slog.w(TAG, "Event report user selecting an invalid package");
return;
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/DeviceStateHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger/DeviceStateHandler.java
new file mode 100644
index 000000000000..66054494c277
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/DeviceStateHandler.java
@@ -0,0 +1,279 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger;
+
+import static android.os.PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED;
+import static android.os.PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED;
+import static android.os.PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.utils.EventLogger;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Manages device state events which require pausing SoundTrigger recognition
+ *
+ * @hide
+ */
+public class DeviceStateHandler implements PhoneCallStateHandler.Callback {
+
+ public static final long CALL_INACTIVE_MSG_DELAY_MS = 1000;
+
+ public interface DeviceStateListener {
+ void onSoundTriggerDeviceStateUpdate(SoundTriggerDeviceState state);
+ }
+
+ public enum SoundTriggerDeviceState {
+ DISABLE, // The device state requires all SoundTrigger sessions are disabled
+ CRITICAL, // The device state requires all non-critical SoundTrigger sessions are disabled
+ ENABLE // The device state permits all SoundTrigger sessions
+ }
+
+ private final Object mLock = new Object();
+
+ private final EventLogger mEventLogger;
+
+ @GuardedBy("mLock")
+ SoundTriggerDeviceState mSoundTriggerDeviceState = SoundTriggerDeviceState.ENABLE;
+
+ // Individual components of the SoundTriggerDeviceState
+ @GuardedBy("mLock")
+ private int mSoundTriggerPowerSaveMode = SOUND_TRIGGER_MODE_ALL_ENABLED;
+
+ @GuardedBy("mLock")
+ private boolean mIsPhoneCallOngoing = false;
+
+ // There can only be one pending notify at any given time.
+ // If any phone state change comes in between, we will cancel the previous pending
+ // task.
+ @GuardedBy("mLock")
+ private NotificationTask mPhoneStateChangePendingNotify = null;
+
+ private Set<DeviceStateListener> mCallbackSet = ConcurrentHashMap.newKeySet(4);
+
+ private final Executor mDelayedNotificationExecutor = Executors.newSingleThreadExecutor();
+
+ private final Executor mCallbackExecutor;
+
+ public void onPowerModeChanged(int soundTriggerPowerSaveMode) {
+ mEventLogger.enqueue(new SoundTriggerPowerEvent(soundTriggerPowerSaveMode));
+ synchronized (mLock) {
+ if (soundTriggerPowerSaveMode == mSoundTriggerPowerSaveMode) {
+ // No state change, nothing to do
+ return;
+ }
+ mSoundTriggerPowerSaveMode = soundTriggerPowerSaveMode;
+ evaluateStateChange();
+ }
+ }
+
+ @Override
+ public void onPhoneCallStateChanged(boolean isInPhoneCall) {
+ mEventLogger.enqueue(new PhoneCallEvent(isInPhoneCall));
+ synchronized (mLock) {
+ if (mIsPhoneCallOngoing == isInPhoneCall) {
+ // no change, nothing to do
+ return;
+ }
+ // Clear any pending notification
+ if (mPhoneStateChangePendingNotify != null) {
+ mPhoneStateChangePendingNotify.cancel();
+ mPhoneStateChangePendingNotify = null;
+ }
+ mIsPhoneCallOngoing = isInPhoneCall;
+ if (!mIsPhoneCallOngoing) {
+ // State has changed from call to no call, delay notification
+ mPhoneStateChangePendingNotify = new NotificationTask(
+ new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ if (mPhoneStateChangePendingNotify != null &&
+ mPhoneStateChangePendingNotify.runnableEquals(this)) {
+
+ mPhoneStateChangePendingNotify = null;
+ evaluateStateChange();
+ }
+ }
+ }
+ },
+ CALL_INACTIVE_MSG_DELAY_MS);
+ mDelayedNotificationExecutor.execute(mPhoneStateChangePendingNotify);
+ } else {
+ evaluateStateChange();
+ }
+ }
+ }
+
+ /** Note, we expect initial callbacks immediately following construction */
+ public DeviceStateHandler(Executor callbackExecutor, EventLogger eventLogger) {
+ mCallbackExecutor = Objects.requireNonNull(callbackExecutor);
+ mEventLogger = Objects.requireNonNull(eventLogger);
+ }
+
+ public SoundTriggerDeviceState getDeviceState() {
+ synchronized (mLock) {
+ return mSoundTriggerDeviceState;
+ }
+ }
+
+ public void registerListener(DeviceStateListener callback) {
+ final var state = getDeviceState();
+ mCallbackExecutor.execute(
+ () -> callback.onSoundTriggerDeviceStateUpdate(state));
+ mCallbackSet.add(callback);
+ }
+
+ public void unregisterListener(DeviceStateListener callback) {
+ mCallbackSet.remove(callback);
+ }
+
+ void dump(PrintWriter pw) {
+ synchronized (mLock) {
+ pw.println("DeviceState: " + mSoundTriggerDeviceState.name());
+ pw.println("PhoneState: " + mIsPhoneCallOngoing);
+ pw.println("PowerSaveMode: " + mSoundTriggerPowerSaveMode);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void evaluateStateChange() {
+ // We should wait until any pending delays are complete to update.
+ // We will eventually get called by the notification task, or something which
+ // cancels it.
+ // Additionally, if there isn't a state change, there is nothing to update.
+ SoundTriggerDeviceState newState = computeState();
+ if (mPhoneStateChangePendingNotify != null || mSoundTriggerDeviceState == newState) {
+ return;
+ }
+
+ mSoundTriggerDeviceState = newState;
+ mEventLogger.enqueue(new DeviceStateEvent(mSoundTriggerDeviceState));
+ final var state = mSoundTriggerDeviceState;
+ for (var callback : mCallbackSet) {
+ mCallbackExecutor.execute(
+ () -> callback.onSoundTriggerDeviceStateUpdate(state));
+ }
+ }
+
+ @GuardedBy("mLock")
+ private SoundTriggerDeviceState computeState() {
+ if (mIsPhoneCallOngoing) {
+ return SoundTriggerDeviceState.DISABLE;
+ }
+ return switch (mSoundTriggerPowerSaveMode) {
+ case SOUND_TRIGGER_MODE_ALL_ENABLED -> SoundTriggerDeviceState.ENABLE;
+ case SOUND_TRIGGER_MODE_CRITICAL_ONLY -> SoundTriggerDeviceState.CRITICAL;
+ case SOUND_TRIGGER_MODE_ALL_DISABLED -> SoundTriggerDeviceState.DISABLE;
+ default -> throw new IllegalStateException(
+ "Received unexpected power state code" + mSoundTriggerPowerSaveMode);
+ };
+ }
+
+ /**
+ * One-shot, cancellable task which runs after a delay. Run must only be called once, from a
+ * single thread. Cancel can be called from any other thread.
+ */
+ private static class NotificationTask implements Runnable {
+ private final Runnable mRunnable;
+ private final long mWaitInMillis;
+
+ private final CountDownLatch mCancelLatch = new CountDownLatch(1);
+
+ NotificationTask(Runnable r, long waitInMillis) {
+ mRunnable = r;
+ mWaitInMillis = waitInMillis;
+ }
+
+ void cancel() {
+ mCancelLatch.countDown();
+ }
+
+ // Used for determining task equality.
+ boolean runnableEquals(Runnable runnable) {
+ return mRunnable == runnable;
+ }
+
+ public void run() {
+ try {
+ if (!mCancelLatch.await(mWaitInMillis, TimeUnit.MILLISECONDS)) {
+ mRunnable.run();
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new AssertionError("Unexpected InterruptedException", e);
+ }
+ }
+ }
+
+ private static class PhoneCallEvent extends EventLogger.Event {
+ final boolean mIsInPhoneCall;
+
+ PhoneCallEvent(boolean isInPhoneCall) {
+ mIsInPhoneCall = isInPhoneCall;
+ }
+
+ @Override
+ public String eventToString() {
+ return "PhoneCallChange - inPhoneCall: " + mIsInPhoneCall;
+ }
+ }
+
+ private static class SoundTriggerPowerEvent extends EventLogger.Event {
+ final int mSoundTriggerPowerState;
+
+ SoundTriggerPowerEvent(int soundTriggerPowerState) {
+ mSoundTriggerPowerState = soundTriggerPowerState;
+ }
+
+ @Override
+ public String eventToString() {
+ return "SoundTriggerPowerChange: " + stateToString();
+ }
+
+ private String stateToString() {
+ return switch (mSoundTriggerPowerState) {
+ case SOUND_TRIGGER_MODE_ALL_ENABLED -> "All enabled";
+ case SOUND_TRIGGER_MODE_CRITICAL_ONLY -> "Critical only";
+ case SOUND_TRIGGER_MODE_ALL_DISABLED -> "All disabled";
+ default -> "Unknown power state: " + mSoundTriggerPowerState;
+ };
+ }
+ }
+
+ private static class DeviceStateEvent extends EventLogger.Event {
+ final SoundTriggerDeviceState mSoundTriggerDeviceState;
+
+ DeviceStateEvent(SoundTriggerDeviceState soundTriggerDeviceState) {
+ mSoundTriggerDeviceState = soundTriggerDeviceState;
+ }
+
+ @Override
+ public String eventToString() {
+ return "DeviceStateChange: " + mSoundTriggerDeviceState.name();
+ }
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java
new file mode 100644
index 000000000000..8773cabeeb92
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java
@@ -0,0 +1,158 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger;
+
+import android.telephony.Annotation;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Handles monitoring telephony call state across active subscriptions.
+ *
+ * @hide
+ */
+public class PhoneCallStateHandler {
+
+ public interface Callback {
+ void onPhoneCallStateChanged(boolean isInPhoneCall);
+ }
+
+ private final Object mLock = new Object();
+
+ // Actually never contended due to executor.
+ @GuardedBy("mLock")
+ private final List<MyCallStateListener> mListenerList = new ArrayList<>();
+
+ private final AtomicBoolean mIsPhoneCallOngoing = new AtomicBoolean(false);
+
+ private final SubscriptionManager mSubscriptionManager;
+ private final TelephonyManager mTelephonyManager;
+ private final Callback mCallback;
+
+ private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+
+ public PhoneCallStateHandler(
+ SubscriptionManager subscriptionManager,
+ TelephonyManager telephonyManager,
+ Callback callback) {
+ mSubscriptionManager = Objects.requireNonNull(subscriptionManager);
+ mTelephonyManager = Objects.requireNonNull(telephonyManager);
+ mCallback = Objects.requireNonNull(callback);
+ mSubscriptionManager.addOnSubscriptionsChangedListener(
+ mExecutor,
+ new SubscriptionManager.OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ updateTelephonyListeners();
+ }
+
+ @Override
+ public void onAddListenerFailed() {
+ Slog.wtf(
+ "SoundTriggerPhoneCallStateHandler",
+ "Failed to add a telephony listener");
+ }
+ });
+ }
+
+ private final class MyCallStateListener extends TelephonyCallback
+ implements TelephonyCallback.CallStateListener {
+
+ final TelephonyManager mTelephonyManagerForSubId;
+
+ // Manager corresponding to the sub-id
+ MyCallStateListener(TelephonyManager telephonyManager) {
+ mTelephonyManagerForSubId = telephonyManager;
+ }
+
+ void cleanup() {
+ mExecutor.execute(() -> mTelephonyManagerForSubId.unregisterTelephonyCallback(this));
+ }
+
+ @Override
+ public void onCallStateChanged(int unused) {
+ updateCallStatus();
+ }
+ }
+
+ /** Compute the current call status, and dispatch callback if it has changed. */
+ private void updateCallStatus() {
+ boolean callStatus = checkCallStatus();
+ if (mIsPhoneCallOngoing.compareAndSet(!callStatus, callStatus)) {
+ mCallback.onPhoneCallStateChanged(callStatus);
+ }
+ }
+
+ /**
+ * Synchronously query the current telephony call state across all subscriptions
+ *
+ * @return - {@code true} if in call, {@code false} if not in call.
+ */
+ private boolean checkCallStatus() {
+ List<SubscriptionInfo> infoList = mSubscriptionManager.getActiveSubscriptionInfoList();
+ if (infoList == null) return false;
+ return infoList.stream()
+ .filter(s -> (s.getSubscriptionId() != SubscriptionManager.INVALID_SUBSCRIPTION_ID))
+ .anyMatch(s -> isCallOngoingFromState(
+ mTelephonyManager
+ .createForSubscriptionId(s.getSubscriptionId())
+ .getCallStateForSubscription()));
+ }
+
+ private void updateTelephonyListeners() {
+ synchronized (mLock) {
+ for (var listener : mListenerList) {
+ listener.cleanup();
+ }
+ mListenerList.clear();
+ List<SubscriptionInfo> infoList = mSubscriptionManager.getActiveSubscriptionInfoList();
+ if (infoList == null) return;
+ infoList.stream()
+ .filter(s -> s.getSubscriptionId()
+ != SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ .map(s -> mTelephonyManager.createForSubscriptionId(s.getSubscriptionId()))
+ .forEach(manager -> {
+ synchronized (mLock) {
+ var listener = new MyCallStateListener(manager);
+ mListenerList.add(listener);
+ manager.registerTelephonyCallback(mExecutor, listener);
+ }
+ });
+ }
+ }
+
+ private static boolean isCallOngoingFromState(@Annotation.CallState int callState) {
+ return switch (callState) {
+ case TelephonyManager.CALL_STATE_IDLE, TelephonyManager.CALL_STATE_RINGING -> false;
+ case TelephonyManager.CALL_STATE_OFFHOOK -> true;
+ default -> throw new IllegalStateException(
+ "Received unexpected call state from Telephony Manager: " + callState);
+ };
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 255db1e4db83..b4066ab1ff39 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -16,15 +16,12 @@
package com.android.server.soundtrigger;
+import static com.android.server.soundtrigger.DeviceStateHandler.SoundTriggerDeviceState;
import static com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent.Type;
import static com.android.server.utils.EventLogger.Event.ALOGW;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
@@ -45,11 +42,7 @@ import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.PowerManager;
-import android.os.PowerManager.SoundTriggerPowerSaveMode;
import android.os.RemoteException;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -99,37 +92,20 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private SoundTriggerModule mModule;
private final Object mLock = new Object();
private final Context mContext;
- private final TelephonyManager mTelephonyManager;
- private final PhoneStateListener mPhoneStateListener;
- private final PowerManager mPowerManager;
// The SoundTriggerManager layer handles multiple recognition models of type generic and
// keyphrase. We store the ModelData here in a hashmap.
- private final HashMap<UUID, ModelData> mModelDataMap;
+ private final HashMap<UUID, ModelData> mModelDataMap = new HashMap<>();
// An index of keyphrase sound models so that we can reach them easily. We support indexing
// keyphrase sound models with a keyphrase ID. Sound model with the same keyphrase ID will
// replace an existing model, thus there is a 1:1 mapping from keyphrase ID to a voice
// sound model.
- private HashMap<Integer, UUID> mKeyphraseUuidMap;
-
- private boolean mCallActive = false;
- private @SoundTriggerPowerSaveMode int mSoundTriggerPowerSaveMode =
- PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED;
+ private final HashMap<Integer, UUID> mKeyphraseUuidMap = new HashMap<>();
// Whether ANY recognition (keyphrase or generic) has been requested.
private boolean mRecognitionRequested = false;
- private PowerSaveModeListener mPowerSaveModeListener;
-
-
- // Handler to process call state changes will delay to allow time for the audio
- // and sound trigger HALs to process the end of call notifications
- // before we re enable pending recognition requests.
- private final Handler mHandler;
- private static final int MSG_CALL_STATE_CHANGED = 0;
- private static final int CALL_INACTIVE_MSG_DELAY_MS = 1000;
-
// TODO(b/269366605) Temporary solution to query correct moduleProperties
private final int mModuleId;
private final Function<SoundTrigger.StatusListener, SoundTriggerModule> mModuleProvider;
@@ -139,16 +115,15 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
@GuardedBy("mLock")
private boolean mIsDetached = false;
+ @GuardedBy("mLock")
+ private SoundTriggerDeviceState mDeviceState = SoundTriggerDeviceState.DISABLE;
+
SoundTriggerHelper(Context context, EventLogger eventLogger,
@NonNull Function<SoundTrigger.StatusListener, SoundTriggerModule> moduleProvider,
int moduleId,
@NonNull Supplier<List<ModuleProperties>> modulePropertiesProvider) {
mModuleId = moduleId;
mContext = context;
- mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mModelDataMap = new HashMap<UUID, ModelData>();
- mKeyphraseUuidMap = new HashMap<Integer, UUID>();
mModuleProvider = moduleProvider;
mEventLogger = eventLogger;
mModulePropertiesProvider = modulePropertiesProvider;
@@ -157,31 +132,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
} else {
mModule = mModuleProvider.apply(this);
}
- Looper looper = Looper.myLooper();
- if (looper == null) {
- looper = Looper.getMainLooper();
- }
- mPhoneStateListener = new MyCallStateListener(looper);
- if (looper != null) {
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_CALL_STATE_CHANGED:
- synchronized (mLock) {
- onCallStateChangedLocked(
- TelephonyManager.CALL_STATE_OFFHOOK == msg.arg1);
- }
- break;
- default:
- Slog.e(TAG, "unknown message in handler:" + msg.what);
- break;
- }
- }
- };
- } else {
- mHandler = null;
- }
}
/**
@@ -373,7 +323,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
modelData.setSoundModel(soundModel);
if (!isRecognitionAllowedByDeviceState(modelData)) {
- initializeDeviceStateListeners();
return STATUS_OK;
}
@@ -497,11 +446,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
modelData.setLoaded();
modelData.clearCallback();
modelData.setRecognitionConfig(null);
-
- if (!computeRecognitionRequestedLocked()) {
- internalClearGlobalStateLocked();
- }
-
return status;
}
}
@@ -638,6 +582,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
}
+ public void onDeviceStateChanged(SoundTriggerDeviceState state) {
+ synchronized (mLock) {
+ if (mIsDetached || mDeviceState == state) {
+ // Nothing to update
+ return;
+ }
+ mDeviceState = state;
+ updateAllRecognitionsLocked();
+ }
+ }
+
public int getGenericModelState(UUID modelId) {
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_get_generic_model_state", 1);
@@ -880,25 +835,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
}
- private void onCallStateChangedLocked(boolean callActive) {
- if (mCallActive == callActive) {
- // We consider multiple call states as being active
- // so we check if something really changed or not here.
- return;
- }
- mCallActive = callActive;
- updateAllRecognitionsLocked();
- }
-
- private void onPowerSaveModeChangedLocked(
- @SoundTriggerPowerSaveMode int soundTriggerPowerSaveMode) {
- if (mSoundTriggerPowerSaveMode == soundTriggerPowerSaveMode) {
- return;
- }
- mSoundTriggerPowerSaveMode = soundTriggerPowerSaveMode;
- updateAllRecognitionsLocked();
- }
-
private void onModelUnloadedLocked(int modelHandle) {
ModelData modelData = getModelDataForLocked(modelHandle);
if (modelData != null) {
@@ -1011,10 +947,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return status;
}
status = startRecognitionLocked(model, notifyClientOnError);
- // Initialize power save, call active state monitoring logic.
- if (status == STATUS_OK) {
- initializeDeviceStateListeners();
- }
return status;
} else {
return stopRecognitionLocked(model, notifyClientOnError);
@@ -1040,7 +972,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
} finally {
internalClearModelStateLocked();
- internalClearGlobalStateLocked();
if (mModule != null) {
mModule.detach();
try {
@@ -1054,24 +985,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
}
- // internalClearGlobalStateLocked() cleans up the telephony and power save listeners.
- private void internalClearGlobalStateLocked() {
- // Unregister from call state changes.
- final long token = Binder.clearCallingIdentity();
- try {
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- // Unregister from power save mode changes.
- if (mPowerSaveModeListener != null) {
- mContext.unregisterReceiver(mPowerSaveModeListener);
- mPowerSaveModeListener = null;
- }
- mRecognitionRequested = false;
- }
-
// Clears state for all models (generic and keyphrase).
private void internalClearModelStateLocked() {
for (ModelData modelData : mModelDataMap.values()) {
@@ -1079,67 +992,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
}
- class MyCallStateListener extends PhoneStateListener {
- MyCallStateListener(@NonNull Looper looper) {
- super(Objects.requireNonNull(looper));
- }
-
- @Override
- public void onCallStateChanged(int state, String arg1) {
-
- if (mHandler != null) {
- synchronized (mLock) {
- mHandler.removeMessages(MSG_CALL_STATE_CHANGED);
- Message msg = mHandler.obtainMessage(MSG_CALL_STATE_CHANGED, state, 0);
- mHandler.sendMessageDelayed(
- msg, (TelephonyManager.CALL_STATE_OFFHOOK == state) ? 0
- : CALL_INACTIVE_MSG_DELAY_MS);
- }
- }
- }
- }
-
- class PowerSaveModeListener extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
- return;
- }
- @SoundTriggerPowerSaveMode int soundTriggerPowerSaveMode =
- mPowerManager.getSoundTriggerPowerSaveMode();
- synchronized (mLock) {
- onPowerSaveModeChangedLocked(soundTriggerPowerSaveMode);
- }
- }
- }
-
- private void initializeDeviceStateListeners() {
- if (mRecognitionRequested) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- // Get the current call state synchronously for the first recognition.
- mCallActive = mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK;
-
- // Register for call state changes when the first call to start recognition occurs.
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
-
- // Register for power saver mode changes when the first call to start recognition
- // occurs.
- if (mPowerSaveModeListener == null) {
- mPowerSaveModeListener = new PowerSaveModeListener();
- mContext.registerReceiver(mPowerSaveModeListener,
- new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
- }
- mSoundTriggerPowerSaveMode = mPowerManager.getSoundTriggerPowerSaveMode();
-
- mRecognitionRequested = true;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
/**
* Stops and unloads all models. This is intended as a clean-up call with the expectation that
* this instance is not used after.
@@ -1153,7 +1005,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
forceStopAndUnloadModelLocked(model, null);
}
mModelDataMap.clear();
- internalClearGlobalStateLocked();
if (mModule != null) {
mModule.detach();
mModule = null;
@@ -1305,28 +1156,14 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
* @param modelData Model data to be used for recognition
* @return True if recognition is allowed to run at this time. False if not.
*/
+ @GuardedBy("mLock")
private boolean isRecognitionAllowedByDeviceState(ModelData modelData) {
- // if mRecognitionRequested is false, call and power state listeners are not registered so
- // we read current state directly from services
- if (!mRecognitionRequested) {
- mCallActive = mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK;
- mSoundTriggerPowerSaveMode = mPowerManager.getSoundTriggerPowerSaveMode();
- }
-
- return !mCallActive && isRecognitionAllowedByPowerState(
- modelData);
- }
-
- /**
- * Helper function to validate if a recognition should run based on the current power state
- *
- * @param modelData Model data to be used for recognition
- * @return True if device state allows recognition to run, false if not.
- */
- private boolean isRecognitionAllowedByPowerState(ModelData modelData) {
- return mSoundTriggerPowerSaveMode == PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED
- || (mSoundTriggerPowerSaveMode == PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY
- && modelData.shouldRunInBatterySaverMode());
+ return switch (mDeviceState) {
+ case DISABLE -> false;
+ case CRITICAL -> modelData.shouldRunInBatterySaverMode();
+ case ENABLE -> true;
+ default -> throw new AssertionError("Enum changed between compile and runtime");
+ };
}
// A single routine that implements the start recognition logic for both generic and keyphrase
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 913535e06a21..3151781ff7ba 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -35,14 +35,18 @@ import static com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent.Typ
import static com.android.server.utils.EventLogger.Event.ALOGW;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.server.soundtrigger.DeviceStateHandler.DeviceStateListener;
+import static com.android.server.soundtrigger.DeviceStateHandler.SoundTriggerDeviceState;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
@@ -85,6 +89,8 @@ import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -112,6 +118,8 @@ import java.util.Objects;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -131,8 +139,8 @@ public class SoundTriggerService extends SystemService {
private static final boolean DEBUG = true;
private static final int SESSION_MAX_EVENT_SIZE = 128;
- final Context mContext;
- private Object mLock;
+ private final Context mContext;
+ private final Object mLock = new Object();
private final SoundTriggerServiceStub mServiceStub;
private final LocalSoundTriggerService mLocalSoundTriggerService;
@@ -140,6 +148,7 @@ public class SoundTriggerService extends SystemService {
private SoundTriggerDbHelper mDbHelper;
private final EventLogger mServiceEventLogger = new EventLogger(256, "Service");
+ private final EventLogger mDeviceEventLogger = new EventLogger(256, "Device Event");
private final Set<EventLogger> mSessionEventLoggers = ConcurrentHashMap.newKeySet(4);
private final Deque<EventLogger> mDetachedSessionEventLoggers = new LinkedBlockingDeque<>(4);
@@ -223,13 +232,18 @@ public class SoundTriggerService extends SystemService {
@GuardedBy("mLock")
private final ArrayMap<String, NumOps> mNumOpsPerPackage = new ArrayMap<>();
+ private final DeviceStateHandler mDeviceStateHandler;
+ private final Executor mDeviceStateHandlerExecutor = Executors.newSingleThreadExecutor();
+ private PhoneCallStateHandler mPhoneCallStateHandler;
+
public SoundTriggerService(Context context) {
super(context);
mContext = context;
mServiceStub = new SoundTriggerServiceStub();
mLocalSoundTriggerService = new LocalSoundTriggerService(context);
- mLock = new Object();
mSoundModelStatTracker = new SoundModelStatTracker();
+ mDeviceStateHandler = new DeviceStateHandler(mDeviceStateHandlerExecutor,
+ mDeviceEventLogger);
}
@Override
@@ -243,6 +257,29 @@ public class SoundTriggerService extends SystemService {
Slog.d(TAG, "onBootPhase: " + phase + " : " + isSafeMode());
if (PHASE_THIRD_PARTY_APPS_CAN_START == phase) {
mDbHelper = new SoundTriggerDbHelper(mContext);
+ final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
+ // Hook up power state listener
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!PowerManager.ACTION_POWER_SAVE_MODE_CHANGED
+ .equals(intent.getAction())) {
+ return;
+ }
+ mDeviceStateHandler.onPowerModeChanged(
+ powerManager.getSoundTriggerPowerSaveMode());
+ }
+ }, new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
+ // Initialize the initial power state
+ // Do so after registering the listener so we ensure that we don't drop any events
+ mDeviceStateHandler.onPowerModeChanged(powerManager.getSoundTriggerPowerSaveMode());
+
+ // PhoneCallStateHandler initializes the original call state
+ mPhoneCallStateHandler = new PhoneCallStateHandler(
+ mContext.getSystemService(SubscriptionManager.class),
+ mContext.getSystemService(TelephonyManager.class),
+ mDeviceStateHandler);
}
mMiddlewareService = ISoundTriggerMiddlewareService.Stub.asInterface(
ServiceManager.waitForService(Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE));
@@ -380,6 +417,9 @@ public class SoundTriggerService extends SystemService {
// Event loggers
pw.println("##Service-Wide logs:");
mServiceEventLogger.dump(pw, /* indent = */ " ");
+ pw.println("\n##Device state logs:");
+ mDeviceStateHandler.dump(pw);
+ mDeviceEventLogger.dump(pw, /* indent = */ " ");
pw.println("\n##Active Session dumps:\n");
for (var sessionLogger : mSessionEventLoggers) {
@@ -403,6 +443,7 @@ public class SoundTriggerService extends SystemService {
class SoundTriggerSessionStub extends ISoundTriggerSession.Stub {
private final SoundTriggerHelper mSoundTriggerHelper;
+ private final DeviceStateListener mListener;
// Used to detect client death.
private final IBinder mClient;
private final Identity mOriginatorIdentity;
@@ -424,6 +465,9 @@ public class SoundTriggerService extends SystemService {
} catch (RemoteException e) {
clientDied();
}
+ mListener = (SoundTriggerDeviceState state)
+ -> mSoundTriggerHelper.onDeviceStateChanged(state);
+ mDeviceStateHandler.registerListener(mListener);
}
@Override
@@ -874,6 +918,7 @@ public class SoundTriggerService extends SystemService {
}
private void detach() {
+ mDeviceStateHandler.unregisterListener(mListener);
mSoundTriggerHelper.detach();
detachSessionLogger(mEventLogger);
}
@@ -890,7 +935,8 @@ public class SoundTriggerService extends SystemService {
private void enforceDetectionPermissions(ComponentName detectionService) {
PackageManager packageManager = mContext.getPackageManager();
String packageName = detectionService.getPackageName();
- if (packageManager.checkPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName)
+ if (packageManager.checkPermission(
+ Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException(detectionService.getPackageName() + " does not have"
+ " permission " + Manifest.permission.CAPTURE_AUDIO_HOTWORD);
@@ -1576,6 +1622,7 @@ public class SoundTriggerService extends SystemService {
private final @NonNull IBinder mClient;
private final EventLogger mEventLogger;
private final Identity mOriginatorIdentity;
+ private final @NonNull DeviceStateListener mListener;
private final SparseArray<UUID> mModelUuid = new SparseArray<>(1);
@@ -1594,6 +1641,9 @@ public class SoundTriggerService extends SystemService {
} catch (RemoteException e) {
clientDied();
}
+ mListener = (SoundTriggerDeviceState state)
+ -> mSoundTriggerHelper.onDeviceStateChanged(state);
+ mDeviceStateHandler.registerListener(mListener);
}
@Override
@@ -1662,6 +1712,7 @@ public class SoundTriggerService extends SystemService {
private void detachInternal() {
mEventLogger.enqueue(new SessionEvent(Type.DETACH, null));
detachSessionLogger(mEventLogger);
+ mDeviceStateHandler.unregisterListener(mListener);
mSoundTriggerHelper.detach();
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
index f3457f5a221b..56a159eb465a 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
@@ -21,6 +21,8 @@ import android.media.soundtrigger.PhraseRecognitionExtra;
import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModelType;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
/**
* Utilities for working with sound trigger related AIDL generated types.
@@ -49,23 +51,29 @@ public class AidlUtil {
/**
* Creates a new generic abort event.
+ *
* @return The new event.
*/
- static RecognitionEvent newAbortEvent() {
- RecognitionEvent event = newEmptyRecognitionEvent();
- event.type = SoundModelType.GENERIC;
- event.status = RecognitionStatus.ABORTED;
- return event;
+ static RecognitionEventSys newAbortEvent() {
+ RecognitionEvent recognitionEvent = newEmptyRecognitionEvent();
+ recognitionEvent.type = SoundModelType.GENERIC;
+ recognitionEvent.status = RecognitionStatus.ABORTED;
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = recognitionEvent;
+ return recognitionEventSys;
}
/**
* Creates a new generic phrase event.
+ *
* @return The new event.
*/
- static PhraseRecognitionEvent newAbortPhraseEvent() {
- PhraseRecognitionEvent event = newEmptyPhraseRecognitionEvent();
- event.common.type = SoundModelType.KEYPHRASE;
- event.common.status = RecognitionStatus.ABORTED;
- return event;
+ static PhraseRecognitionEventSys newAbortPhraseEvent() {
+ PhraseRecognitionEvent recognitionEvent = newEmptyPhraseRecognitionEvent();
+ recognitionEvent.common.type = SoundModelType.KEYPHRASE;
+ recognitionEvent.common.status = RecognitionStatus.ABORTED;
+ PhraseRecognitionEventSys phraseRecognitionEventSys = new PhraseRecognitionEventSys();
+ phraseRecognitionEventSys.phraseRecognitionEvent = recognitionEvent;
+ return phraseRecognitionEventSys;
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
index 75206e69bc6a..6f4a94692c4b 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
@@ -20,12 +20,12 @@ import android.hardware.soundtrigger3.ISoundTriggerHw;
import android.hardware.soundtrigger3.ISoundTriggerHwCallback;
import android.hardware.soundtrigger3.ISoundTriggerHwGlobalCallback;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.IBinder;
/**
@@ -173,14 +173,19 @@ interface ISoundTriggerHal {
*/
interface ModelCallback {
/**
- * @see ISoundTriggerHwCallback#recognitionCallback(int, RecognitionEvent)
+ * Decorated callback of
+ * {@link ISoundTriggerHwCallback#recognitionCallback(int, RecognitionEvent)} where
+ * {@link RecognitionEventSys} is decorating the returned {@link RecognitionEvent}
*/
- void recognitionCallback(int modelHandle, RecognitionEvent event);
+ void recognitionCallback(int modelHandle, RecognitionEventSys event);
/**
- * @see ISoundTriggerHwCallback#phraseRecognitionCallback(int, PhraseRecognitionEvent)
+ * Decorated callback of
+ * {@link ISoundTriggerHwCallback#phraseRecognitionCallback(int, PhraseRecognitionEvent)}
+ * where {@link PhraseRecognitionEventSys} is decorating the returned
+ * {@link PhraseRecognitionEvent}
*/
- void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEvent event);
+ void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEventSys event);
/**
* @see ISoundTriggerHwCallback#modelUnloaded(int)
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
index 8c7cabeee320..d8ef2b6640fd 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
@@ -19,14 +19,14 @@ package com.android.server.soundtrigger_middleware;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.SoundModelType;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.IBinder;
import java.util.HashSet;
@@ -238,13 +238,13 @@ public class SoundTriggerHalConcurrentCaptureHandler implements ISoundTriggerHal
}
@Override
- public void recognitionCallback(int modelHandle, RecognitionEvent event) {
+ public void recognitionCallback(int modelHandle, RecognitionEventSys event) {
synchronized (mActiveModels) {
if (!mActiveModels.contains(modelHandle)) {
// Discard the event.
return;
}
- if (!event.recognitionStillActive) {
+ if (!event.recognitionEvent.recognitionStillActive) {
mActiveModels.remove(modelHandle);
}
// A recognition event must be the last one for its model, unless it indicates that
@@ -255,13 +255,13 @@ public class SoundTriggerHalConcurrentCaptureHandler implements ISoundTriggerHal
}
@Override
- public void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEvent event) {
+ public void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEventSys event) {
synchronized (mActiveModels) {
if (!mActiveModels.contains(modelHandle)) {
// Discard the event.
return;
}
- if (!event.common.recognitionStillActive) {
+ if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
mActiveModels.remove(modelHandle);
}
// A recognition event must be the last one for its model, unless it indicates that
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
index 24741e1caea9..bac24669696c 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
@@ -17,14 +17,14 @@
package com.android.server.soundtrigger_middleware;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.DeadObjectException;
import android.os.IBinder;
import android.util.Log;
@@ -253,7 +253,7 @@ public class SoundTriggerHalEnforcer implements ISoundTriggerHal {
}
@Override
- public void recognitionCallback(int model, RecognitionEvent event) {
+ public void recognitionCallback(int model, RecognitionEventSys event) {
synchronized (mModelStates) {
ModelState state = mModelStates.get(model);
if (state == null || state == ModelState.INACTIVE) {
@@ -261,15 +261,16 @@ public class SoundTriggerHalEnforcer implements ISoundTriggerHal {
reboot();
return;
}
- if (event.recognitionStillActive && event.status != RecognitionStatus.SUCCESS
- && event.status != RecognitionStatus.FORCED) {
+ if (event.recognitionEvent.recognitionStillActive
+ && event.recognitionEvent.status != RecognitionStatus.SUCCESS
+ && event.recognitionEvent.status != RecognitionStatus.FORCED) {
Log.wtfStack(TAG,
"recognitionStillActive is only allowed when the recognition status "
+ "is SUCCESS");
reboot();
return;
}
- if (!event.recognitionStillActive) {
+ if (!event.recognitionEvent.recognitionStillActive) {
mModelStates.replace(model, ModelState.INACTIVE);
}
}
@@ -278,7 +279,7 @@ public class SoundTriggerHalEnforcer implements ISoundTriggerHal {
}
@Override
- public void phraseRecognitionCallback(int model, PhraseRecognitionEvent event) {
+ public void phraseRecognitionCallback(int model, PhraseRecognitionEventSys event) {
synchronized (mModelStates) {
ModelState state = mModelStates.get(model);
if (state == null || state == ModelState.INACTIVE) {
@@ -286,16 +287,16 @@ public class SoundTriggerHalEnforcer implements ISoundTriggerHal {
reboot();
return;
}
- if (event.common.recognitionStillActive
- && event.common.status != RecognitionStatus.SUCCESS
- && event.common.status != RecognitionStatus.FORCED) {
+ if (event.phraseRecognitionEvent.common.recognitionStillActive
+ && event.phraseRecognitionEvent.common.status != RecognitionStatus.SUCCESS
+ && event.phraseRecognitionEvent.common.status != RecognitionStatus.FORCED) {
Log.wtfStack(TAG,
"recognitionStillActive is only allowed when the recognition status "
+ "is SUCCESS");
reboot();
return;
}
- if (!event.common.recognitionStillActive) {
+ if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
mModelStates.replace(model, ModelState.INACTIVE);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
index c67bdd76eee8..df2e9b41662b 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
@@ -25,9 +25,12 @@ import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.IBinder;
import android.os.IHwBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.system.OsConstants;
import android.util.Log;
@@ -570,16 +573,20 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHal {
public void recognitionCallback_2_1(
android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event,
int cookie) {
- mDelegate.recognitionCallback(event.header.model,
- ConversionUtil.hidl2aidlRecognitionEvent(event));
+ RecognitionEventSys eventSys = new RecognitionEventSys();
+ eventSys.recognitionEvent = ConversionUtil.hidl2aidlRecognitionEvent(event);
+ eventSys.halEventReceivedMillis = SystemClock.elapsedRealtime();
+ mDelegate.recognitionCallback(event.header.model, eventSys);
}
@Override
public void phraseRecognitionCallback_2_1(
android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent event,
int cookie) {
- mDelegate.phraseRecognitionCallback(event.common.header.model,
- ConversionUtil.hidl2aidlPhraseRecognitionEvent(event));
+ PhraseRecognitionEventSys eventSys = new PhraseRecognitionEventSys();
+ eventSys.phraseRecognitionEvent = ConversionUtil.hidl2aidlPhraseRecognitionEvent(event);
+ eventSys.halEventReceivedMillis = SystemClock.elapsedRealtime();
+ mDelegate.phraseRecognitionCallback(event.common.header.model, eventSys);
}
@Override
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
index 8bb5eb191858..b1165bb57628 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
@@ -29,9 +29,12 @@ import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.os.SystemClock;
public class SoundTriggerHw3Compat implements ISoundTriggerHal {
private final @NonNull ISoundTriggerHw mDriver;
@@ -244,14 +247,20 @@ public class SoundTriggerHw3Compat implements ISoundTriggerHal {
public void phraseRecognitionCallback(int model, PhraseRecognitionEvent event) {
// A FORCED status implies that recognition is still active after the event.
event.common.recognitionStillActive |= event.common.status == RecognitionStatus.FORCED;
- mDelegate.phraseRecognitionCallback(model, event);
+ PhraseRecognitionEventSys phraseRecognitionEventSys = new PhraseRecognitionEventSys();
+ phraseRecognitionEventSys.phraseRecognitionEvent = event;
+ phraseRecognitionEventSys.halEventReceivedMillis = SystemClock.elapsedRealtimeNanos();
+ mDelegate.phraseRecognitionCallback(model, phraseRecognitionEventSys);
}
@Override
public void recognitionCallback(int model, RecognitionEvent event) {
// A FORCED status implies that recognition is still active after the event.
event.recognitionStillActive |= event.status == RecognitionStatus.FORCED;
- mDelegate.recognitionCallback(model, event);
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = event;
+ recognitionEventSys.halEventReceivedMillis = SystemClock.elapsedRealtimeNanos();
+ mDelegate.recognitionCallback(model, recognitionEventSys);
}
@Override
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
index 0e796d1afbd6..2ee4e3cff02c 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -16,12 +16,24 @@
package com.android.server.soundtrigger_middleware;
-import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.*;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.DETACH;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.FORCE_RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.GET_MODEL_PARAMETER;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.LOAD_MODEL;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.LOAD_PHRASE_MODEL;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.MODEL_UNLOADED;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.MODULE_DIED;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.QUERY_MODEL_PARAMETER;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.RESOURCES_AVAILABLE;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.SET_MODEL_PARAMETER;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.START_RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.STOP_RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.UNLOAD_MODEL;
import static com.android.server.utils.EventLogger.Event.ALOGI;
import static com.android.server.utils.EventLogger.Event.ALOGW;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.Context;
import android.media.permission.Identity;
import android.media.permission.IdentityContext;
@@ -29,11 +41,12 @@ import android.media.soundtrigger.ModelParameterRange;
import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.BatteryStatsInternal;
import android.os.IBinder;
@@ -45,19 +58,18 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.LatencyTracker;
import com.android.server.LocalServices;
-import com.android.server.utils.EventLogger.Event;
import com.android.server.utils.EventLogger;
-
+import com.android.server.utils.EventLogger.Event;
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.Deque;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
-import java.util.Deque;
/**
@@ -370,7 +382,7 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
}
@Override
- public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
+ public void onRecognition(int modelHandle, RecognitionEventSys event, int captureSession)
throws RemoteException {
try {
mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
@@ -388,13 +400,13 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
}
@Override
- public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
+ public void onPhraseRecognition(int modelHandle, PhraseRecognitionEventSys event,
int captureSession)
throws RemoteException {
try {
mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
- startKeyphraseEventLatencyTracking(event);
+ startKeyphraseEventLatencyTracking(event.phraseRecognitionEvent);
mCallbackDelegate.onPhraseRecognition(modelHandle, event, captureSession);
mEventLogger.enqueue(SessionEvent.createForVoid(
RECOGNITION, modelHandle, event, captureSession)
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 00cedd77414e..00b894e1c6b5 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -27,15 +27,15 @@ import android.media.permission.Identity;
import android.media.permission.IdentityContext;
import android.media.permission.PermissionUtil;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.IBinder;
import android.os.RemoteException;
@@ -307,16 +307,15 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware
}
@Override
- public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
- throws RemoteException {
+ public void onRecognition(int modelHandle, RecognitionEventSys event,
+ int captureSession) throws RemoteException {
enforcePermissions("Sound trigger recognition.");
mDelegate.onRecognition(modelHandle, event, captureSession);
}
@Override
- public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
- int captureSession)
- throws RemoteException {
+ public void onPhraseRecognition(int modelHandle, PhraseRecognitionEventSys event,
+ int captureSession) throws RemoteException {
enforcePermissions("Sound trigger phrase recognition.");
mDelegate.onPhraseRecognition(modelHandle, event, captureSession);
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 15c9ba923d3a..f208c03024b2 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -21,17 +21,17 @@ import android.annotation.Nullable;
import android.media.permission.Identity;
import android.media.permission.IdentityContext;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.IBinder;
import android.os.RemoteException;
@@ -710,8 +710,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
}
}
- class CallbackWrapper implements ISoundTriggerCallback,
- IBinder.DeathRecipient {
+ class CallbackWrapper implements ISoundTriggerCallback, IBinder.DeathRecipient {
private final ISoundTriggerCallback mCallback;
CallbackWrapper(ISoundTriggerCallback callback) {
@@ -728,11 +727,11 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
}
@Override
- public void onRecognition(int modelHandle, @NonNull RecognitionEvent event,
+ public void onRecognition(int modelHandle, @NonNull RecognitionEventSys event,
int captureSession) {
synchronized (SoundTriggerMiddlewareValidation.this) {
ModelState modelState = mLoadedModels.get(modelHandle);
- if (!event.recognitionStillActive) {
+ if (!event.recognitionEvent.recognitionStillActive) {
modelState.activityState = ModelState.Activity.LOADED;
}
}
@@ -744,7 +743,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
Log.w(TAG, "Client callback exception.", e);
synchronized (SoundTriggerMiddlewareValidation.this) {
ModelState modelState = mLoadedModels.get(modelHandle);
- if (event.status != RecognitionStatus.FORCED) {
+ if (event.recognitionEvent.status != RecognitionStatus.FORCED) {
modelState.activityState = ModelState.Activity.INTERCEPTED;
// If we failed to deliver an actual event to the client, they would
// never know to restart it whenever circumstances change. Thus, we
@@ -758,10 +757,10 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
@Override
public void onPhraseRecognition(int modelHandle,
- @NonNull PhraseRecognitionEvent event, int captureSession) {
+ @NonNull PhraseRecognitionEventSys event, int captureSession) {
synchronized (SoundTriggerMiddlewareValidation.this) {
ModelState modelState = mLoadedModels.get(modelHandle);
- if (!event.common.recognitionStillActive) {
+ if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
modelState.activityState = ModelState.Activity.LOADED;
}
}
@@ -773,7 +772,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
Log.w(TAG, "Client callback exception.", e);
synchronized (SoundTriggerMiddlewareValidation.this) {
ModelState modelState = mLoadedModels.get(modelHandle);
- if (!event.common.recognitionStillActive) {
+ if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
modelState.activityState = ModelState.Activity.INTERCEPTED;
// If we failed to deliver an actual event to the client, they would
// never know to restart it whenever circumstances change. Thus, we
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index 6223b2e8ace4..84cec5592831 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -19,16 +19,16 @@ package com.android.server.soundtrigger_middleware;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.SoundModelType;
import android.media.soundtrigger.Status;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -499,10 +499,10 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
@Override
public void recognitionCallback(int modelHandle,
- @NonNull RecognitionEvent recognitionEvent) {
+ @NonNull RecognitionEventSys event) {
ISoundTriggerCallback callback;
synchronized (SoundTriggerModule.this) {
- if (!recognitionEvent.recognitionStillActive) {
+ if (!event.recognitionEvent.recognitionStillActive) {
setState(ModelState.LOADED);
}
callback = mCallback;
@@ -510,7 +510,7 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
// The callback must be invoked outside of the lock.
try {
if (callback != null) {
- callback.onRecognition(mHandle, recognitionEvent, mSession.mSessionHandle);
+ callback.onRecognition(mHandle, event, mSession.mSessionHandle);
}
} catch (RemoteException e) {
// We're not expecting any exceptions here.
@@ -520,10 +520,10 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
@Override
public void phraseRecognitionCallback(int modelHandle,
- @NonNull PhraseRecognitionEvent phraseRecognitionEvent) {
+ @NonNull PhraseRecognitionEventSys event) {
ISoundTriggerCallback callback;
synchronized (SoundTriggerModule.this) {
- if (!phraseRecognitionEvent.common.recognitionStillActive) {
+ if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
setState(ModelState.LOADED);
}
callback = mCallback;
@@ -532,8 +532,7 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
// The callback must be invoked outside of the lock.
try {
if (callback != null) {
- mCallback.onPhraseRecognition(mHandle, phraseRecognitionEvent,
- mSession.mSessionHandle);
+ mCallback.onPhraseRecognition(mHandle, event, mSession.mSessionHandle);
}
} catch (RemoteException e) {
// We're not expecting any exceptions here.
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java
index c228dafcee8e..61f34c2570ff 100644
--- a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java
@@ -40,6 +40,8 @@ public class RemoteWallpaperEffectsGenerationService extends
private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+ private static final long TIMEOUT_IDLE_BIND_MILLIS = 120 * DateUtils.SECOND_IN_MILLIS;
+
private final RemoteWallpaperEffectsGenerationServiceCallback mCallback;
public RemoteWallpaperEffectsGenerationService(Context context,
@@ -62,7 +64,7 @@ public class RemoteWallpaperEffectsGenerationService extends
@Override
protected long getTimeoutIdleBindMillis() {
- return PERMANENT_BOUND_TIMEOUT_MS;
+ return TIMEOUT_IDLE_BIND_MILLIS;
}
@Override
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 2704418935d9..6997f3c79bc3 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -360,6 +360,11 @@ public final class DisconnectCause {
*/
public static final int INCOMING_AUTO_REJECTED = 81;
+ /**
+ * Indicates that the call was unable to be made because the satellite modem is enabled.
+ * @hide
+ */
+ public static final int SATELLITE_ENABLED = 82;
//*********************************************************************************************
// When adding a disconnect type:
@@ -379,168 +384,170 @@ public final class DisconnectCause {
@UnsupportedAppUsage
public static @NonNull String toString(int cause) {
switch (cause) {
- case NOT_DISCONNECTED:
- return "NOT_DISCONNECTED";
- case INCOMING_MISSED:
- return "INCOMING_MISSED";
- case NORMAL:
- return "NORMAL";
- case LOCAL:
- return "LOCAL";
- case BUSY:
- return "BUSY";
- case CONGESTION:
- return "CONGESTION";
- case INVALID_NUMBER:
- return "INVALID_NUMBER";
- case NUMBER_UNREACHABLE:
- return "NUMBER_UNREACHABLE";
- case SERVER_UNREACHABLE:
- return "SERVER_UNREACHABLE";
- case INVALID_CREDENTIALS:
- return "INVALID_CREDENTIALS";
- case OUT_OF_NETWORK:
- return "OUT_OF_NETWORK";
- case SERVER_ERROR:
- return "SERVER_ERROR";
- case TIMED_OUT:
- return "TIMED_OUT";
- case LOST_SIGNAL:
- return "LOST_SIGNAL";
- case LIMIT_EXCEEDED:
- return "LIMIT_EXCEEDED";
- case INCOMING_REJECTED:
- return "INCOMING_REJECTED";
- case POWER_OFF:
- return "POWER_OFF";
- case OUT_OF_SERVICE:
- return "OUT_OF_SERVICE";
- case ICC_ERROR:
- return "ICC_ERROR";
- case CALL_BARRED:
- return "CALL_BARRED";
- case FDN_BLOCKED:
- return "FDN_BLOCKED";
- case CS_RESTRICTED:
- return "CS_RESTRICTED";
- case CS_RESTRICTED_NORMAL:
- return "CS_RESTRICTED_NORMAL";
- case CS_RESTRICTED_EMERGENCY:
- return "CS_RESTRICTED_EMERGENCY";
- case UNOBTAINABLE_NUMBER:
- return "UNOBTAINABLE_NUMBER";
- case CDMA_LOCKED_UNTIL_POWER_CYCLE:
- return "CDMA_LOCKED_UNTIL_POWER_CYCLE";
- case CDMA_DROP:
- return "CDMA_DROP";
- case CDMA_INTERCEPT:
- return "CDMA_INTERCEPT";
- case CDMA_REORDER:
- return "CDMA_REORDER";
- case CDMA_SO_REJECT:
- return "CDMA_SO_REJECT";
- case CDMA_RETRY_ORDER:
- return "CDMA_RETRY_ORDER";
- case CDMA_ACCESS_FAILURE:
- return "CDMA_ACCESS_FAILURE";
- case CDMA_PREEMPTED:
- return "CDMA_PREEMPTED";
- case CDMA_NOT_EMERGENCY:
- return "CDMA_NOT_EMERGENCY";
- case CDMA_ACCESS_BLOCKED:
- return "CDMA_ACCESS_BLOCKED";
- case EMERGENCY_ONLY:
- return "EMERGENCY_ONLY";
- case NO_PHONE_NUMBER_SUPPLIED:
- return "NO_PHONE_NUMBER_SUPPLIED";
- case DIALED_MMI:
- return "DIALED_MMI";
- case VOICEMAIL_NUMBER_MISSING:
- return "VOICEMAIL_NUMBER_MISSING";
- case CDMA_CALL_LOST:
- return "CDMA_CALL_LOST";
- case EXITED_ECM:
- return "EXITED_ECM";
- case DIAL_MODIFIED_TO_USSD:
- return "DIAL_MODIFIED_TO_USSD";
- case DIAL_MODIFIED_TO_SS:
- return "DIAL_MODIFIED_TO_SS";
- case DIAL_MODIFIED_TO_DIAL:
- return "DIAL_MODIFIED_TO_DIAL";
- case DIAL_MODIFIED_TO_DIAL_VIDEO:
- return "DIAL_MODIFIED_TO_DIAL_VIDEO";
- case DIAL_VIDEO_MODIFIED_TO_SS:
- return "DIAL_VIDEO_MODIFIED_TO_SS";
- case DIAL_VIDEO_MODIFIED_TO_USSD:
- return "DIAL_VIDEO_MODIFIED_TO_USSD";
- case DIAL_VIDEO_MODIFIED_TO_DIAL:
- return "DIAL_VIDEO_MODIFIED_TO_DIAL";
- case DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO:
- return "DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO";
- case ERROR_UNSPECIFIED:
- return "ERROR_UNSPECIFIED";
- case OUTGOING_FAILURE:
- return "OUTGOING_FAILURE";
- case OUTGOING_CANCELED:
- return "OUTGOING_CANCELED";
- case IMS_MERGED_SUCCESSFULLY:
- return "IMS_MERGED_SUCCESSFULLY";
- case CDMA_ALREADY_ACTIVATED:
- return "CDMA_ALREADY_ACTIVATED";
- case VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED:
- return "VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED";
- case CALL_PULLED:
- return "CALL_PULLED";
- case ANSWERED_ELSEWHERE:
- return "ANSWERED_ELSEWHERE";
- case MAXIMUM_NUMBER_OF_CALLS_REACHED:
- return "MAXIMUM_NUMER_OF_CALLS_REACHED";
- case DATA_DISABLED:
- return "DATA_DISABLED";
- case DATA_LIMIT_REACHED:
- return "DATA_LIMIT_REACHED";
- case DIALED_CALL_FORWARDING_WHILE_ROAMING:
- return "DIALED_CALL_FORWARDING_WHILE_ROAMING";
- case IMEI_NOT_ACCEPTED:
- return "IMEI_NOT_ACCEPTED";
- case WIFI_LOST:
- return "WIFI_LOST";
- case IMS_ACCESS_BLOCKED:
- return "IMS_ACCESS_BLOCKED";
- case LOW_BATTERY:
- return "LOW_BATTERY";
- case DIAL_LOW_BATTERY:
- return "DIAL_LOW_BATTERY";
- case EMERGENCY_TEMP_FAILURE:
- return "EMERGENCY_TEMP_FAILURE";
- case EMERGENCY_PERM_FAILURE:
- return "EMERGENCY_PERM_FAILURE";
- case NORMAL_UNSPECIFIED:
- return "NORMAL_UNSPECIFIED";
- case IMS_SIP_ALTERNATE_EMERGENCY_CALL:
- return "IMS_SIP_ALTERNATE_EMERGENCY_CALL";
- case ALREADY_DIALING:
- return "ALREADY_DIALING";
- case CANT_CALL_WHILE_RINGING:
- return "CANT_CALL_WHILE_RINGING";
- case CALLING_DISABLED:
- return "CALLING_DISABLED";
- case TOO_MANY_ONGOING_CALLS:
- return "TOO_MANY_ONGOING_CALLS";
- case OTASP_PROVISIONING_IN_PROCESS:
- return "OTASP_PROVISIONING_IN_PROCESS";
- case MEDIA_TIMEOUT:
- return "MEDIA_TIMEOUT";
- case EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE:
- return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE";
- case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
- return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION";
- case OUTGOING_EMERGENCY_CALL_PLACED:
- return "OUTGOING_EMERGENCY_CALL_PLACED";
+ case NOT_DISCONNECTED:
+ return "NOT_DISCONNECTED";
+ case INCOMING_MISSED:
+ return "INCOMING_MISSED";
+ case NORMAL:
+ return "NORMAL";
+ case LOCAL:
+ return "LOCAL";
+ case BUSY:
+ return "BUSY";
+ case CONGESTION:
+ return "CONGESTION";
+ case INVALID_NUMBER:
+ return "INVALID_NUMBER";
+ case NUMBER_UNREACHABLE:
+ return "NUMBER_UNREACHABLE";
+ case SERVER_UNREACHABLE:
+ return "SERVER_UNREACHABLE";
+ case INVALID_CREDENTIALS:
+ return "INVALID_CREDENTIALS";
+ case OUT_OF_NETWORK:
+ return "OUT_OF_NETWORK";
+ case SERVER_ERROR:
+ return "SERVER_ERROR";
+ case TIMED_OUT:
+ return "TIMED_OUT";
+ case LOST_SIGNAL:
+ return "LOST_SIGNAL";
+ case LIMIT_EXCEEDED:
+ return "LIMIT_EXCEEDED";
+ case INCOMING_REJECTED:
+ return "INCOMING_REJECTED";
+ case POWER_OFF:
+ return "POWER_OFF";
+ case OUT_OF_SERVICE:
+ return "OUT_OF_SERVICE";
+ case ICC_ERROR:
+ return "ICC_ERROR";
+ case CALL_BARRED:
+ return "CALL_BARRED";
+ case FDN_BLOCKED:
+ return "FDN_BLOCKED";
+ case CS_RESTRICTED:
+ return "CS_RESTRICTED";
+ case CS_RESTRICTED_NORMAL:
+ return "CS_RESTRICTED_NORMAL";
+ case CS_RESTRICTED_EMERGENCY:
+ return "CS_RESTRICTED_EMERGENCY";
+ case UNOBTAINABLE_NUMBER:
+ return "UNOBTAINABLE_NUMBER";
+ case CDMA_LOCKED_UNTIL_POWER_CYCLE:
+ return "CDMA_LOCKED_UNTIL_POWER_CYCLE";
+ case CDMA_DROP:
+ return "CDMA_DROP";
+ case CDMA_INTERCEPT:
+ return "CDMA_INTERCEPT";
+ case CDMA_REORDER:
+ return "CDMA_REORDER";
+ case CDMA_SO_REJECT:
+ return "CDMA_SO_REJECT";
+ case CDMA_RETRY_ORDER:
+ return "CDMA_RETRY_ORDER";
+ case CDMA_ACCESS_FAILURE:
+ return "CDMA_ACCESS_FAILURE";
+ case CDMA_PREEMPTED:
+ return "CDMA_PREEMPTED";
+ case CDMA_NOT_EMERGENCY:
+ return "CDMA_NOT_EMERGENCY";
+ case CDMA_ACCESS_BLOCKED:
+ return "CDMA_ACCESS_BLOCKED";
+ case EMERGENCY_ONLY:
+ return "EMERGENCY_ONLY";
+ case NO_PHONE_NUMBER_SUPPLIED:
+ return "NO_PHONE_NUMBER_SUPPLIED";
+ case DIALED_MMI:
+ return "DIALED_MMI";
+ case VOICEMAIL_NUMBER_MISSING:
+ return "VOICEMAIL_NUMBER_MISSING";
+ case CDMA_CALL_LOST:
+ return "CDMA_CALL_LOST";
+ case EXITED_ECM:
+ return "EXITED_ECM";
+ case DIAL_MODIFIED_TO_USSD:
+ return "DIAL_MODIFIED_TO_USSD";
+ case DIAL_MODIFIED_TO_SS:
+ return "DIAL_MODIFIED_TO_SS";
+ case DIAL_MODIFIED_TO_DIAL:
+ return "DIAL_MODIFIED_TO_DIAL";
+ case DIAL_MODIFIED_TO_DIAL_VIDEO:
+ return "DIAL_MODIFIED_TO_DIAL_VIDEO";
+ case DIAL_VIDEO_MODIFIED_TO_SS:
+ return "DIAL_VIDEO_MODIFIED_TO_SS";
+ case DIAL_VIDEO_MODIFIED_TO_USSD:
+ return "DIAL_VIDEO_MODIFIED_TO_USSD";
+ case DIAL_VIDEO_MODIFIED_TO_DIAL:
+ return "DIAL_VIDEO_MODIFIED_TO_DIAL";
+ case DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO:
+ return "DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO";
+ case ERROR_UNSPECIFIED:
+ return "ERROR_UNSPECIFIED";
+ case OUTGOING_FAILURE:
+ return "OUTGOING_FAILURE";
+ case OUTGOING_CANCELED:
+ return "OUTGOING_CANCELED";
+ case IMS_MERGED_SUCCESSFULLY:
+ return "IMS_MERGED_SUCCESSFULLY";
+ case CDMA_ALREADY_ACTIVATED:
+ return "CDMA_ALREADY_ACTIVATED";
+ case VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED:
+ return "VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED";
+ case CALL_PULLED:
+ return "CALL_PULLED";
+ case ANSWERED_ELSEWHERE:
+ return "ANSWERED_ELSEWHERE";
+ case MAXIMUM_NUMBER_OF_CALLS_REACHED:
+ return "MAXIMUM_NUMER_OF_CALLS_REACHED";
+ case DATA_DISABLED:
+ return "DATA_DISABLED";
+ case DATA_LIMIT_REACHED:
+ return "DATA_LIMIT_REACHED";
+ case DIALED_CALL_FORWARDING_WHILE_ROAMING:
+ return "DIALED_CALL_FORWARDING_WHILE_ROAMING";
+ case IMEI_NOT_ACCEPTED:
+ return "IMEI_NOT_ACCEPTED";
+ case WIFI_LOST:
+ return "WIFI_LOST";
+ case IMS_ACCESS_BLOCKED:
+ return "IMS_ACCESS_BLOCKED";
+ case LOW_BATTERY:
+ return "LOW_BATTERY";
+ case DIAL_LOW_BATTERY:
+ return "DIAL_LOW_BATTERY";
+ case EMERGENCY_TEMP_FAILURE:
+ return "EMERGENCY_TEMP_FAILURE";
+ case EMERGENCY_PERM_FAILURE:
+ return "EMERGENCY_PERM_FAILURE";
+ case NORMAL_UNSPECIFIED:
+ return "NORMAL_UNSPECIFIED";
+ case IMS_SIP_ALTERNATE_EMERGENCY_CALL:
+ return "IMS_SIP_ALTERNATE_EMERGENCY_CALL";
+ case ALREADY_DIALING:
+ return "ALREADY_DIALING";
+ case CANT_CALL_WHILE_RINGING:
+ return "CANT_CALL_WHILE_RINGING";
+ case CALLING_DISABLED:
+ return "CALLING_DISABLED";
+ case TOO_MANY_ONGOING_CALLS:
+ return "TOO_MANY_ONGOING_CALLS";
+ case OTASP_PROVISIONING_IN_PROCESS:
+ return "OTASP_PROVISIONING_IN_PROCESS";
+ case MEDIA_TIMEOUT:
+ return "MEDIA_TIMEOUT";
+ case EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE:
+ return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE";
+ case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
+ return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION";
+ case OUTGOING_EMERGENCY_CALL_PLACED:
+ return "OUTGOING_EMERGENCY_CALL_PLACED";
case INCOMING_AUTO_REJECTED:
return "INCOMING_AUTO_REJECTED";
- default:
- return "INVALID: " + cause;
+ case SATELLITE_ENABLED:
+ return "SATELLITE_ENABLED";
+ default:
+ return "INVALID: " + cause;
}
}
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index c5830b8249c8..431e9e628962 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -1503,6 +1503,31 @@ public class SatelliteManager {
}
}
+ /**
+ * Inform whether the device is aligned with the satellite for demo mode.
+ *
+ * @param isAligned {@true} Device is aligned with the satellite for demo mode
+ * {@false} Device is not aligned with the satellite for demo mode
+ *
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+
+ public void onDeviceAlignedWithSatellite(boolean isAligned) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.onDeviceAlignedWithSatellite(mSubId, isAligned);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("informDeviceAlignedToSatellite() RemoteException:" + ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
.getTelephonyServiceManager()
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 18e4c37f3e23..21aad73ce005 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2982,6 +2982,16 @@ interface ITelephony {
void requestTimeForNextSatelliteVisibility(int subId, in ResultReceiver receiver);
/**
+ * Inform whether the device is aligned with the satellite within in margin for demo mode.
+ *
+ * @param isAligned {@true} Device is aligned with the satellite for demo mode
+ * {@false} Device is not aligned with the satellite for demo mode
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void onDeviceAlignedWithSatellite(int subId, in boolean isAligned);
+
+ /**
* This API can be used by only CTS to update satellite vendor service package name.
*
* @param servicePackageName The package name of the satellite vendor service.
@@ -3018,4 +3028,13 @@ interface ITelephony {
* {@code false} otherwise.
*/
boolean setSatellitePointingUiClassName(in String packageName, in String className);
+
+ /**
+ * This API can be used by only CTS to update the timeout duration in milliseconds whether
+ * the device is aligned with the satellite for demo mode
+ *
+ * @param timeoutMillis The timeout duration in millisecond.
+ * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
+ */
+ boolean setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis);
}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index 7272abba897d..32ff243921ec 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -21,6 +21,9 @@
<option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
<!-- Ensure output directory is empty at the start -->
<option name="run-command" value="rm -rf /sdcard/flicker" />
+ <!-- Increase trace size: 20mb for WM and 80mb for SF -->
+ <option name="run-command" value="cmd window tracing size 20480" />
+ <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
index a3fb73bad25f..496165ab5b09 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
@@ -18,6 +18,11 @@ package com.android.server.wm.flicker.ime
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
+import android.platform.test.annotations.Postsubmit
+import android.tools.common.Timestamp
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.common.flicker.subject.exceptions.ExceptionMessageBuilder
+import android.tools.common.flicker.subject.exceptions.InvalidPropertyException
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
@@ -36,7 +41,7 @@ import org.junit.runners.Parameterized
/**
* Test IME window layer will become visible when switching from the fixed orientation activity
* (e.g. Launcher activity). To run this test: `atest
- * FlickerTests:OpenImeWindowFromFixedOrientationAppTest`
+ * FlickerTests:ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@@ -77,6 +82,49 @@ open class ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest(flicker: Fl
flicker.snapshotStartingWindowLayerCoversExactlyOnApp(imeTestApp)
}
+ @Postsubmit
+ @Test
+ fun imeLayerAlphaOneAfterSnapshotStartingWindowRemoval() {
+ // Check if the snapshot appeared during the trace
+ var imeSnapshotRemovedTimestamp: Timestamp? = null
+
+ val layerTrace = flicker.reader.readLayersTrace()
+ val layerTraceEntries = layerTrace?.entries?.toList() ?: emptyList()
+
+ layerTraceEntries.zipWithNext { prev, next ->
+ val prevSnapshotLayerVisible =
+ ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(prev.visibleLayers)
+ val nextSnapshotLayerVisible =
+ ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(next.visibleLayers)
+
+ if (imeSnapshotRemovedTimestamp == null &&
+ (prevSnapshotLayerVisible && !nextSnapshotLayerVisible)) {
+ imeSnapshotRemovedTimestamp = next.timestamp
+ }
+ }
+
+ // if so, make an assertion
+ imeSnapshotRemovedTimestamp?.let { timestamp ->
+ val stateAfterSnapshot = layerTrace?.getEntryAt(timestamp)
+ ?: error("State not found for $timestamp")
+
+ val imeLayers = ComponentNameMatcher.IME
+ .filterLayers(stateAfterSnapshot.visibleLayers.toList())
+
+ require(imeLayers.isNotEmpty()) { "IME layer not found" }
+ if (imeLayers.any { it.color.a != 1.0f }) {
+ val errorMsgBuilder = ExceptionMessageBuilder()
+ .setTimestamp(timestamp)
+ .forInvalidProperty("IME layer alpha")
+ .setExpected("is 1.0")
+ .setActual("not 1.0")
+ .addExtraDescription("Filter",
+ ComponentNameMatcher.IME.toLayerIdentifier())
+ throw InvalidPropertyException(errorMsgBuilder)
+ }
+ }
+ }
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
index 017de605fe39..e2d17cdbe9e6 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
@@ -26,39 +26,57 @@ import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RenderNode;
import android.graphics.Shader;
+import android.graphics.SurfaceTexture;
import android.hardware.HardwareBuffer;
import android.media.Image;
import android.media.ImageWriter;
import android.os.Bundle;
+import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.TextureView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
@SuppressWarnings({"UnusedDeclaration"})
public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callback,
- AdapterView.OnItemSelectedListener {
+ TextureView.SurfaceTextureListener {
private static final int WIDTH = 512;
private static final int HEIGHT = 512;
private ImageView mImageView;
private SurfaceView mSurfaceView;
+ private TextureView mTextureView;
private HardwareBuffer mGradientBuffer;
- private ImageWriter mImageWriter;
+ private Map<View, ImageWriter> mImageWriters = new HashMap<>();
private ColorSpace mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
private String[] mColorNames = {"sRGB", "BT2020_HLG", "BT2020_PQ"};
- private String mCurrentColorName = "sRGB";
- private FutureTask<HardwareBuffer> authorGradientBuffer(HardwareBuffer buffer) {
+ private int mGradientEndColor = 0xFFFFFFFF;
+
+ private int[] mGradientEndColors = {0xFFFFFFFF, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF};
+ private String[] mGradientColorNames = {"Grayscale", "Red", "Green", "Blue"};
+
+ private final ExecutorService mBufferFenceExecutor = Executors.newFixedThreadPool(1);
+ private final ExecutorService mBufferExecutor = Executors.newFixedThreadPool(1);
+
+ private FutureTask<HardwareBuffer> authorGradientBuffer(
+ HardwareBuffer buffer, int gradentEndColor) {
HardwareBufferRenderer renderer = new HardwareBufferRenderer(buffer);
RenderNode node = new RenderNode("content");
node.setPosition(0, 0, buffer.getWidth(), buffer.getHeight());
@@ -66,9 +84,10 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
Canvas canvas = node.beginRecording();
LinearGradient gradient = new LinearGradient(
0, 0, buffer.getWidth(), buffer.getHeight(), 0xFF000000,
- 0xFFFFFFFF, Shader.TileMode.CLAMP);
+ gradentEndColor, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(gradient);
+ paint.setDither(true);
canvas.drawRect(0f, 0f, buffer.getWidth(), buffer.getHeight(), paint);
node.endRecording();
@@ -78,7 +97,7 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
FutureTask<HardwareBuffer> resolvedBuffer = new FutureTask<>(() -> buffer);
renderer.obtainRenderRequest()
.setColorSpace(colorSpace)
- .draw(Executors.newSingleThreadExecutor(), result -> {
+ .draw(mBufferFenceExecutor, result -> {
result.getFence().await(Duration.ofSeconds(3));
resolvedBuffer.run();
});
@@ -90,7 +109,7 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
WIDTH, HEIGHT, PixelFormat.RGBA_8888, 1,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
| HardwareBuffer.USAGE_GPU_COLOR_OUTPUT);
- return authorGradientBuffer(buffer);
+ return authorGradientBuffer(buffer, mGradientEndColor);
}
@Override
@@ -101,29 +120,70 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
- ArrayAdapter<String> adapter = new ArrayAdapter<>(
+ ArrayAdapter<String> colorSpaceAdapter = new ArrayAdapter<>(
this, android.R.layout.simple_spinner_item, mColorNames);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- Spinner spinner = new Spinner(this);
- spinner.setAdapter(adapter);
- spinner.setOnItemSelectedListener(this);
+ colorSpaceAdapter
+ .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ Spinner colorSpaceSpinner = new Spinner(this);
+ colorSpaceSpinner.setAdapter(colorSpaceAdapter);
+ colorSpaceSpinner.setOnItemSelectedListener(new ColorSpaceOnItemSelectedListener());
+
+ ArrayAdapter<String> gradientColorAdapter = new ArrayAdapter<>(
+ this, android.R.layout.simple_spinner_item, mGradientColorNames);
+
+ gradientColorAdapter
+ .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ Spinner gradientColorSpinner = new Spinner(this);
+ gradientColorSpinner.setAdapter(gradientColorAdapter);
+ gradientColorSpinner
+ .setOnItemSelectedListener(new GradientColorOnItemSelectedListener());
mGradientBuffer = getGradientBuffer().get();
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
+ TextView imageViewText = new TextView(this);
+ imageViewText.setText("ImageView");
mImageView = new ImageView(this);
+ TextView textureViewText = new TextView(this);
+ textureViewText.setText("TextureView");
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+
+ TextView surfaceViewText = new TextView(this);
+ surfaceViewText.setText("SurfaceView");
mSurfaceView = new SurfaceView(this);
mSurfaceView.getHolder().addCallback(this);
- linearLayout.addView(spinner, new LinearLayout.LayoutParams(
+ LinearLayout spinnerLayout = new LinearLayout(this);
+ spinnerLayout.setOrientation(LinearLayout.HORIZONTAL);
+
+ spinnerLayout.addView(colorSpaceSpinner, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+
+ spinnerLayout.addView(gradientColorSpinner, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+
+ linearLayout.addView(spinnerLayout, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
+ linearLayout.addView(imageViewText, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(mImageView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
+ linearLayout.addView(textureViewText, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+ linearLayout.addView(mTextureView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
+ linearLayout.addView(surfaceViewText, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(mSurfaceView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
setContentView(linearLayout);
@@ -145,16 +205,24 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
}
private void populateBuffers() {
- Bitmap bitmap = Bitmap.wrapHardwareBuffer(
- mGradientBuffer, ColorSpace.get(ColorSpace.Named.SRGB));
- Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, false);
- copy.setColorSpace(mColorSpace);
- mImageView.setImageBitmap(copy);
-
- try (Image image = mImageWriter.dequeueInputImage()) {
- authorGradientBuffer(image.getHardwareBuffer()).get();
- image.setDataSpace(mColorSpace.getDataSpace());
- mImageWriter.queueInputImage(image);
+ try {
+ Bitmap bitmap = Bitmap.wrapHardwareBuffer(
+ getGradientBuffer().get(), ColorSpace.get(ColorSpace.Named.SRGB));
+ Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, false);
+ copy.setColorSpace(mColorSpace);
+ mImageView.setImageBitmap(copy);
+
+ for (ImageWriter writer : mImageWriters.values()) {
+ mBufferExecutor.execute(() -> {
+ try (Image image = writer.dequeueInputImage()) {
+ authorGradientBuffer(image.getHardwareBuffer(), mGradientEndColor).get();
+ image.setDataSpace(mColorSpace.getDataSpace());
+ writer.queueInputImage(image);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -167,30 +235,81 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- mImageWriter = new ImageWriter.Builder(holder.getSurface())
+ mImageWriters.put(mSurfaceView, new ImageWriter.Builder(holder.getSurface())
.setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
| HardwareBuffer.USAGE_GPU_COLOR_OUTPUT
| HardwareBuffer.USAGE_COMPOSER_OVERLAY)
- .build();
+ .build());
populateBuffers();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
- mImageWriter.close();
- mImageWriter = null;
+ if (mImageWriters.containsKey(mSurfaceView)) {
+ mImageWriters.remove(mSurfaceView);
+ }
}
-
@Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- mCurrentColorName = mColorNames[position];
- mColorSpace = getFromName(mCurrentColorName);
+ public void onSurfaceTextureAvailable(
+ @NonNull SurfaceTexture surface, int width, int height) {
+ mImageWriters.put(mTextureView, new ImageWriter.Builder(new Surface(surface))
+ .setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
+ | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)
+ .build());
populateBuffers();
}
@Override
- public void onNothingSelected(AdapterView<?> parent) {
+ public void onSurfaceTextureSizeChanged(
+ @NonNull SurfaceTexture surface, int width, int height) {
+
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
+ if (mImageWriters.containsKey(mTextureView)) {
+ mImageWriters.remove(mTextureView);
+ }
+ return false;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
+
+ }
+
+ private final class ColorSpaceOnItemSelectedListener
+ implements AdapterView.OnItemSelectedListener {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ ColorBitmapActivity.this.mColorSpace =
+ getFromName(ColorBitmapActivity.this.mColorNames[position]);
+ ColorBitmapActivity.this.getMainExecutor()
+ .execute(ColorBitmapActivity.this::populateBuffers);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+
+ }
+ }
+
+ private final class GradientColorOnItemSelectedListener
+ implements AdapterView.OnItemSelectedListener {
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ ColorBitmapActivity.this.mGradientEndColor =
+ ColorBitmapActivity.this.mGradientEndColors[position];
+ ColorBitmapActivity.this.getMainExecutor()
+ .execute(ColorBitmapActivity.this::populateBuffers);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+
+ }
}
}
diff --git a/tests/SilkFX/res/layout/gainmap_image.xml b/tests/SilkFX/res/layout/gainmap_image.xml
index 89bbb709d0bf..b0ed9147585e 100644
--- a/tests/SilkFX/res/layout/gainmap_image.xml
+++ b/tests/SilkFX/res/layout/gainmap_image.xml
@@ -34,7 +34,7 @@
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content"
- android:text="SDR original" />
+ android:text="SDR" />
<RadioButton android:id="@+id/output_gainmap"
android:layout_width="wrap_content"
@@ -46,13 +46,34 @@
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content"
- android:text="HDR (sdr+gainmap)" />
+ android:text="HDR" />
+
+ <RadioButton android:id="@+id/output_hdr_test"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="HDR (test)" />
</RadioGroup>
- <Spinner
- android:id="@+id/image_selection"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Spinner
+ android:id="@+id/image_selection"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content" />
+
+ <Button
+ android:id="@+id/gainmap_metadata"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="Gainmap Metadata..." />
+
+ </LinearLayout>
<TextView
android:id="@+id/error_msg"
@@ -67,4 +88,4 @@
</LinearLayout>
-</com.android.test.silkfx.hdr.GainmapImage> \ No newline at end of file
+</com.android.test.silkfx.hdr.GainmapImage>
diff --git a/tests/SilkFX/res/layout/gainmap_metadata.xml b/tests/SilkFX/res/layout/gainmap_metadata.xml
new file mode 100644
index 000000000000..0dabaca457f0
--- /dev/null
+++ b/tests/SilkFX/res/layout/gainmap_metadata.xml
@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:layout_width="350dp"
+ android:layout_height="300dp"
+ android:layout_centerHorizontal="true"
+ android:padding="8dp"
+ android:orientation="vertical"
+ android:background="#444444">
+
+ <TextView
+ android:id="@+id/gainmap_metadata_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:text="Metadata for &quot;HDR (test)&quot; (values in linear space):" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/gainmap_metadata_gainmapmin_text"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="Gain Map Min:" />
+
+ <TextView
+ android:id="@+id/gainmap_metadata_gainmapmin_val"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ems="4"
+ android:text="TODO" />
+
+ <SeekBar
+ android:id="@+id/gainmap_metadata_gainmapmin"
+ android:min="0"
+ android:max="100"
+ android:layout_width="150dp"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/gainmap_metadata_gainmapmax_text"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="Gain Map Max:" />
+
+ <TextView
+ android:id="@+id/gainmap_metadata_gainmapmax_val"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ems="4"
+ android:text="TODO" />
+
+ <SeekBar
+ android:id="@+id/gainmap_metadata_gainmapmax"
+ android:min="0"
+ android:max="100"
+ android:layout_width="150dp"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/gainmap_metadata_capacitymin_text"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="Capacity Min:" />
+
+ <TextView
+ android:id="@+id/gainmap_metadata_capacitymin_val"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ems="4"
+ android:text="TODO" />
+
+ <SeekBar
+ android:id="@+id/gainmap_metadata_capacitymin"
+ android:min="0"
+ android:max="100"
+ android:layout_width="150dp"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/gainmap_metadata_capacitymax_text"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="Capacity Max:" />
+
+ <TextView
+ android:id="@+id/gainmap_metadata_capacitymax_val"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ems="4"
+ android:text="TODO" />
+
+ <SeekBar
+ android:id="@+id/gainmap_metadata_capacitymax"
+ android:min="0"
+ android:max="100"
+ android:layout_width="150dp"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/gainmap_metadata_gamma_text"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="Gamma:" />
+
+ <TextView
+ android:id="@+id/gainmap_metadata_gamma_val"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ems="4"
+ android:text="TODO" />
+
+ <SeekBar
+ android:id="@+id/gainmap_metadata_gamma"
+ android:min="0"
+ android:max="100"
+ android:layout_width="150dp"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/gainmap_metadata_offsetsdr_text"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="Offset SDR:" />
+
+ <TextView
+ android:id="@+id/gainmap_metadata_offsetsdr_val"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ems="4"
+ android:text="TODO" />
+
+ <SeekBar
+ android:id="@+id/gainmap_metadata_offsetsdr"
+ android:min="0"
+ android:max="100"
+ android:layout_width="150dp"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/gainmap_metadata_offsethdr_text"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="Offset HDR:" />
+
+ <TextView
+ android:id="@+id/gainmap_metadata_offsethdr_val"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ems="4"
+ android:text="TODO" />
+
+ <SeekBar
+ android:id="@+id/gainmap_metadata_offsethdr"
+ android:min="0"
+ android:max="100"
+ android:layout_width="150dp"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/gainmap_metadata_reset"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="Reset" />
+
+ <Button
+ android:id="@+id/gainmap_metadata_done"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="Done" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt
index 78bc4c45fa4f..7cf69b7780d9 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt
@@ -27,6 +27,7 @@ import android.util.AttributeSet
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
+import android.widget.Button
import android.widget.FrameLayout
import android.widget.RadioGroup
import android.widget.Spinner
@@ -44,6 +45,7 @@ class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context
private var gainmap: Gainmap? = null
private var gainmapVisualizer: Bitmap? = null
private lateinit var imageView: SubsamplingScaleImageView
+ private lateinit var gainmapMetadataEditor: GainmapMetadataEditor
init {
gainmapImages = context.assets.list("gainmaps")!!
@@ -58,6 +60,7 @@ class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context
super.onFinishInflate()
imageView = findViewById(R.id.image)!!
+ gainmapMetadataEditor = GainmapMetadataEditor(this, imageView)
findViewById<RadioGroup>(R.id.output_mode)!!.also {
it.check(outputMode)
@@ -92,6 +95,10 @@ class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context
}
}
+ findViewById<Button>(R.id.gainmap_metadata)!!.setOnClickListener {
+ gainmapMetadataEditor.openEditor()
+ }
+
setImage(0)
imageView.apply {
@@ -132,6 +139,7 @@ class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context
findViewById<RadioGroup>(R.id.output_mode)!!.visibility = View.VISIBLE
gainmap = bitmap!!.gainmap
+ gainmapMetadataEditor.setGainmap(gainmap)
val map = gainmap!!.gainmapContents
if (map.config != Bitmap.Config.ALPHA_8) {
gainmapVisualizer = map
@@ -175,7 +183,15 @@ class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context
imageView.setImage(ImageSource.cachedBitmap(when (outputMode) {
R.id.output_hdr -> {
- bitmap!!.gainmap = gainmap; bitmap!!
+ gainmapMetadataEditor.useOriginalMetadata()
+ bitmap!!.gainmap = gainmap
+ bitmap!!
+ }
+
+ R.id.output_hdr_test -> {
+ gainmapMetadataEditor.useEditMetadata()
+ bitmap!!.gainmap = gainmap
+ bitmap!!
}
R.id.output_sdr -> {
@@ -186,4 +202,4 @@ class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context
else -> throw IllegalStateException()
}))
}
-} \ No newline at end of file
+}
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt
new file mode 100644
index 000000000000..8a653045c97b
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.silkfx.hdr
+
+import android.graphics.Gainmap
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.PopupWindow
+import android.widget.SeekBar
+import android.widget.TextView
+import com.android.test.silkfx.R
+
+data class GainmapMetadata(
+ var ratioMin: Float,
+ var ratioMax: Float,
+ var capacityMin: Float,
+ var capacityMax: Float,
+ var gamma: Float,
+ var offsetSdr: Float,
+ var offsetHdr: Float
+)
+
+class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
+ private var gainmap: Gainmap? = null
+ private var showingEdits = false
+
+ private var metadataPopup: PopupWindow? = null
+
+ private var originalMetadata: GainmapMetadata = GainmapMetadata(
+ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f)
+ private var currentMetadata: GainmapMetadata = originalMetadata.copy()
+
+ private val maxProgress = 100.0f
+
+ private val minRatioMin = .001f
+ private val maxRatioMin = 1.0f
+ private val minRatioMax = 1.0f
+ private val maxRatioMax = 16.0f
+ private val minCapacityMin = 1.0f
+ private val maxCapacityMin = maxRatioMax
+ private val minCapacityMax = 1.001f
+ private val maxCapacityMax = maxRatioMax
+ private val minGamma = 0.1f
+ private val maxGamma = 3.0f
+ // Min and max offsets are 0.0 and 1.0 respectively
+
+ fun setGainmap(newGainmap: Gainmap?) {
+ gainmap = newGainmap
+ originalMetadata = GainmapMetadata(gainmap!!.getRatioMin()[0],
+ gainmap!!.getRatioMax()[0], gainmap!!.getMinDisplayRatioForHdrTransition(),
+ gainmap!!.getDisplayRatioForFullHdr(), gainmap!!.getGamma()[0],
+ gainmap!!.getEpsilonSdr()[0], gainmap!!.getEpsilonHdr()[0])
+ currentMetadata = originalMetadata.copy()
+ }
+
+ fun useOriginalMetadata() {
+ showingEdits = false
+ applyMetadata(originalMetadata)
+ }
+
+ fun useEditMetadata() {
+ showingEdits = true
+ applyMetadata(currentMetadata)
+ }
+
+ fun closeEditor() {
+ metadataPopup?.let {
+ it.dismiss()
+ metadataPopup = null
+ }
+ }
+
+ fun openEditor() {
+ if (metadataPopup != null) return
+
+ val view = LayoutInflater.from(parent.getContext()).inflate(R.layout.gainmap_metadata, null)
+
+ metadataPopup = PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT)
+ metadataPopup!!.showAtLocation(view, Gravity.CENTER, 0, 0)
+
+ (view.getParent() as ViewGroup).removeView(view)
+ parent.addView(view)
+
+ view.findViewById<Button>(R.id.gainmap_metadata_done)!!.setOnClickListener {
+ closeEditor()
+ }
+
+ view.findViewById<Button>(R.id.gainmap_metadata_reset)!!.setOnClickListener {
+ resetGainmapMetadata()
+ }
+
+ updateMetadataUi()
+
+ val gainmapMinSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmin)
+ val gainmapMaxSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmax)
+ val capacityMinSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymin)
+ val capacityMaxSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymax)
+ val gammaSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_gamma)
+ val offsetSdrSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_offsetsdr)
+ val offsetHdrSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_offsethdr)
+ arrayOf(gainmapMinSeek, gainmapMaxSeek, capacityMinSeek, capacityMaxSeek, gammaSeek,
+ offsetSdrSeek, offsetHdrSeek).forEach {
+ it.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
+ override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ if (!fromUser) return
+ val normalized = progress.toFloat() / maxProgress
+ when (seekBar) {
+ gainmapMinSeek -> updateGainmapMin(normalized)
+ gainmapMaxSeek -> updateGainmapMax(normalized)
+ capacityMinSeek -> updateCapacityMin(normalized)
+ capacityMaxSeek -> updateCapacityMax(normalized)
+ gammaSeek -> updateGamma(normalized)
+ offsetSdrSeek -> updateOffsetSdr(normalized)
+ offsetHdrSeek -> updateOffsetHdr(normalized)
+ }
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar) {}
+ override fun onStopTrackingTouch(seekBar: SeekBar) {}
+ })
+ }
+ }
+
+ private fun updateMetadataUi() {
+ val gainmapMinSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmin)
+ val gainmapMaxSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmax)
+ val capacityMinSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymin)
+ val capacityMaxSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymax)
+ val gammaSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_gamma)
+ val offsetSdrSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_offsetsdr)
+ val offsetHdrSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_offsethdr)
+
+ gainmapMinSeek.setProgress(
+ ((currentMetadata.ratioMin - minRatioMin) / maxRatioMin * maxProgress).toInt())
+ gainmapMaxSeek.setProgress(
+ ((currentMetadata.ratioMax - minRatioMax) / maxRatioMax * maxProgress).toInt())
+ capacityMinSeek.setProgress(
+ ((currentMetadata.capacityMin - minCapacityMin) / maxCapacityMin * maxProgress).toInt())
+ capacityMaxSeek.setProgress(
+ ((currentMetadata.capacityMax - minCapacityMax) / maxCapacityMax * maxProgress).toInt())
+ gammaSeek.setProgress(
+ ((currentMetadata.gamma - minGamma) / maxGamma * maxProgress).toInt())
+ // Log base 3 via: log_b(x) = log_y(x) / log_y(b)
+ offsetSdrSeek.setProgress(
+ ((1.0 - Math.log(currentMetadata.offsetSdr.toDouble() / Math.log(3.0)) / -11.0)
+ .toFloat() * maxProgress).toInt())
+ offsetHdrSeek.setProgress(
+ ((1.0 - Math.log(currentMetadata.offsetHdr.toDouble() / Math.log(3.0)) / -11.0)
+ .toFloat() * maxProgress).toInt())
+
+ parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmin_val)!!.setText(
+ "%.3f".format(currentMetadata.ratioMin))
+ parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmax_val)!!.setText(
+ "%.3f".format(currentMetadata.ratioMax))
+ parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymin_val)!!.setText(
+ "%.3f".format(currentMetadata.capacityMin))
+ parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymax_val)!!.setText(
+ "%.3f".format(currentMetadata.capacityMax))
+ parent.findViewById<TextView>(R.id.gainmap_metadata_gamma_val)!!.setText(
+ "%.3f".format(currentMetadata.gamma))
+ parent.findViewById<TextView>(R.id.gainmap_metadata_offsetsdr_val)!!.setText(
+ "%.5f".format(currentMetadata.offsetSdr))
+ parent.findViewById<TextView>(R.id.gainmap_metadata_offsethdr_val)!!.setText(
+ "%.5f".format(currentMetadata.offsetHdr))
+ }
+
+ private fun resetGainmapMetadata() {
+ currentMetadata = originalMetadata.copy()
+ applyMetadata(currentMetadata)
+ updateMetadataUi()
+ }
+
+ private fun applyMetadata(newMetadata: GainmapMetadata) {
+ gainmap!!.setRatioMin(newMetadata.ratioMin, newMetadata.ratioMin, newMetadata.ratioMin)
+ gainmap!!.setRatioMax(newMetadata.ratioMax, newMetadata.ratioMax, newMetadata.ratioMax)
+ gainmap!!.setMinDisplayRatioForHdrTransition(newMetadata.capacityMin)
+ gainmap!!.setDisplayRatioForFullHdr(newMetadata.capacityMax)
+ gainmap!!.setGamma(newMetadata.gamma, newMetadata.gamma, newMetadata.gamma)
+ gainmap!!.setEpsilonSdr(newMetadata.offsetSdr, newMetadata.offsetSdr, newMetadata.offsetSdr)
+ gainmap!!.setEpsilonHdr(newMetadata.offsetHdr, newMetadata.offsetHdr, newMetadata.offsetHdr)
+ renderView.invalidate()
+ }
+
+ private fun updateGainmapMin(normalized: Float) {
+ val newValue = minRatioMin + normalized * (maxRatioMin - minRatioMin)
+ parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmin_val)!!.setText(
+ "%.3f".format(newValue))
+ currentMetadata.ratioMin = newValue
+ if (showingEdits) {
+ gainmap!!.setRatioMin(newValue, newValue, newValue)
+ renderView.invalidate()
+ }
+ }
+
+ private fun updateGainmapMax(normalized: Float) {
+ val newValue = minRatioMax + normalized * (maxRatioMax - minRatioMax)
+ parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmax_val)!!.setText(
+ "%.3f".format(newValue))
+ currentMetadata.ratioMax = newValue
+ if (showingEdits) {
+ gainmap!!.setRatioMax(newValue, newValue, newValue)
+ renderView.invalidate()
+ }
+ }
+
+ private fun updateCapacityMin(normalized: Float) {
+ val newValue = minCapacityMin + normalized * (maxCapacityMin - minCapacityMin)
+ parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymin_val)!!.setText(
+ "%.3f".format(newValue))
+ currentMetadata.capacityMin = newValue
+ if (showingEdits) {
+ gainmap!!.setMinDisplayRatioForHdrTransition(newValue)
+ renderView.invalidate()
+ }
+ }
+
+ private fun updateCapacityMax(normalized: Float) {
+ val newValue = minCapacityMax + normalized * (maxCapacityMax - minCapacityMax)
+ parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymax_val)!!.setText(
+ "%.3f".format(newValue))
+ currentMetadata.capacityMax = newValue
+ if (showingEdits) {
+ gainmap!!.setDisplayRatioForFullHdr(newValue)
+ renderView.invalidate()
+ }
+ }
+
+ private fun updateGamma(normalized: Float) {
+ val newValue = minGamma + normalized * (maxGamma - minGamma)
+ parent.findViewById<TextView>(R.id.gainmap_metadata_gamma_val)!!.setText(
+ "%.3f".format(newValue))
+ currentMetadata.gamma = newValue
+ if (showingEdits) {
+ gainmap!!.setGamma(newValue, newValue, newValue)
+ renderView.invalidate()
+ }
+ }
+
+ private fun updateOffsetSdr(normalized: Float) {
+ var newValue = 0.0f
+ if (normalized > 0.0f ) {
+ newValue = Math.pow(3.0, (1.0 - normalized.toDouble()) * -11.0).toFloat()
+ }
+ parent.findViewById<TextView>(R.id.gainmap_metadata_offsetsdr_val)!!.setText(
+ "%.5f".format(newValue))
+ currentMetadata.offsetSdr = newValue
+ if (showingEdits) {
+ gainmap!!.setEpsilonSdr(newValue, newValue, newValue)
+ renderView.invalidate()
+ }
+ }
+
+ private fun updateOffsetHdr(normalized: Float) {
+ var newValue = 0.0f
+ if (normalized > 0.0f ) {
+ newValue = Math.pow(3.0, (1.0 - normalized.toDouble()) * -11.0).toFloat()
+ }
+ parent.findViewById<TextView>(R.id.gainmap_metadata_offsethdr_val)!!.setText(
+ "%.5f".format(newValue))
+ currentMetadata.offsetHdr = newValue
+ if (showingEdits) {
+ gainmap!!.setEpsilonHdr(newValue, newValue, newValue)
+ renderView.invalidate()
+ }
+ }
+}