summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/statsd/Android.bp3
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp6
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h8
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.h10
-rw-r--r--cmds/statsd/src/condition/ConditionTracker.h5
-rw-r--r--cmds/statsd/src/condition/ConditionWizard.h6
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.h11
-rw-r--r--cmds/statsd/src/config/ConfigListener.h2
-rw-r--r--cmds/statsd/src/flags/flags.cpp37
-rw-r--r--cmds/statsd/src/flags/flags.h36
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp88
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h13
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp1
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h6
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h2
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp18
-rw-r--r--cmds/statsd/tests/ConfigManager_test.cpp14
-rw-r--r--cmds/statsd/tests/e2e/ConfigUpdate_e2e_ab_test.cpp328
-rw-r--r--cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp523
-rw-r--r--cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp23
-rw-r--r--cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp52
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp42
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp15
-rw-r--r--cmds/statsd/tests/statsd_test_util.h2
-rw-r--r--core/api/current.txt58
-rw-r--r--core/api/system-current.txt36
-rw-r--r--core/api/test-current.txt6
-rw-r--r--core/java/android/app/ActivityThread.java17
-rw-r--r--core/java/android/app/IApplicationThread.aidl4
-rw-r--r--core/java/android/app/Notification.java24
-rw-r--r--core/java/android/app/SystemServiceRegistry.java9
-rw-r--r--core/java/android/bluetooth/BluetoothLeAudio.java451
-rw-r--r--core/java/android/bluetooth/BluetoothProfile.java9
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/content/ContextWrapper.java143
-rw-r--r--core/java/android/content/pm/PackageManager.java14
-rw-r--r--core/java/android/hardware/display/DisplayManager.java61
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java27
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl6
-rw-r--r--core/java/android/inputmethodservice/AbstractInputMethodService.java3
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java33
-rw-r--r--core/java/android/net/CaptivePortal.java16
-rw-r--r--core/java/android/net/ConnectivityManager.java2
-rw-r--r--core/java/android/os/PowerManager.java2
-rw-r--r--core/java/android/provider/Settings.java9
-rw-r--r--core/java/android/util/imetracing/ImeTracing.java9
-rw-r--r--core/java/android/util/imetracing/ImeTracingClientImpl.java10
-rw-r--r--core/java/android/util/imetracing/ImeTracingServerImpl.java6
-rw-r--r--core/java/android/util/imetracing/InputConnectionHelper.java231
-rw-r--r--core/java/android/uwb/UwbManager.java32
-rw-r--r--core/java/android/view/Display.java3
-rw-r--r--core/java/android/view/InsetsController.java14
-rw-r--r--core/java/android/view/ThreadedRenderer.java8
-rw-r--r--core/java/android/view/View.java26
-rw-r--r--core/java/android/view/ViewFrameInfo.java81
-rw-r--r--core/java/android/view/ViewRootImpl.java30
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java25
-rw-r--r--core/java/android/widget/TextView.java3
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java34
-rw-r--r--core/java/com/android/internal/app/ChooserListAdapter.java13
-rw-r--r--core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java9
-rw-r--r--core/java/com/android/internal/view/IInputConnectionWrapper.java44
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java75
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java4
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java14
-rw-r--r--core/proto/android/inputmethodservice/inputmethodservice.proto2
-rw-r--r--core/proto/android/view/inputmethod/inputconnection.proto64
-rw-r--r--core/proto/android/view/inputmethod/inputmethodeditortrace.proto1
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--core/res/res/values-night/colors.xml3
-rw-r--r--core/res/res/values-night/values.xml8
-rw-r--r--core/res/res/values/colors.xml2
-rw-r--r--core/res/res/values/colors_device_defaults.xml8
-rw-r--r--core/res/res/values/config.xml11
-rw-r--r--core/res/res/values/strings.xml9
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--core/res/res/values/themes_device_defaults.xml7
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java4
-rw-r--r--core/tests/uwbtests/src/android/uwb/UwbManagerTest.java49
-rw-r--r--core/tests/uwbtests/src/android/uwb/UwbTestUtils.java7
-rw-r--r--graphics/java/android/graphics/FrameInfo.java40
-rw-r--r--graphics/java/android/graphics/Typeface.java7
-rw-r--r--libs/WindowManager/Shell/Android.bp3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java106
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java36
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java)68
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java69
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java)163
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java98
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt95
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt104
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java4
-rw-r--r--libs/hwui/FrameInfo.cpp6
-rw-r--r--libs/hwui/FrameInfo.h3
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java11
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java2
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/AndroidManifest.xml14
-rw-r--r--packages/SystemUI/res-keyguard/color/notification_background_dimmed_color.xml (renamed from packages/SystemUI/res/color/background_protect_secondary.xml)5
-rw-r--r--packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml4
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml6
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml3
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml35
-rw-r--r--packages/SystemUI/res/color/pin_delete_color.xml2
-rw-r--r--packages/SystemUI/res/color/pin_divider_color.xml2
-rw-r--r--packages/SystemUI/res/color/qs_background_dark.xml2
-rw-r--r--packages/SystemUI/res/drawable/notification_guts_bg.xml2
-rw-r--r--packages/SystemUI/res/drawable/notification_material_bg.xml2
-rw-r--r--packages/SystemUI/res/drawable/notification_material_bg_dim.xml2
-rw-r--r--packages/SystemUI/res/drawable/qs_navbar_scrim.xml25
-rw-r--r--packages/SystemUI/res/layout/app_ops_info.xml2
-rw-r--r--packages/SystemUI/res/layout/feedback_info.xml2
-rw-r--r--packages/SystemUI/res/layout/notification_conversation_info.xml2
-rw-r--r--packages/SystemUI/res/layout/notification_guts.xml3
-rw-r--r--packages/SystemUI/res/layout/notification_snooze.xml2
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml8
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_section_header.xml1
-rw-r--r--packages/SystemUI/res/values-night/colors.xml11
-rw-r--r--packages/SystemUI/res/values/colors.xml9
-rw-r--r--packages/SystemUI/res/values/styles.xml9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/EmergencyButton.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java7
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java21
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java30
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java28
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadKey.java22
-rw-r--r--packages/SystemUI/src/com/android/keyguard/PasswordTextView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java)54
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java)8
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java)8
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java)14
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java)6
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java)9
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java)10
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java)13
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java)7
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java)8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LogConfig.java64
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java255
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java87
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java200
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java164
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java)6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java)6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java)7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java)6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java)6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java)7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBufferTest.java)4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java)7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java)5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java19
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationPromptController.java5
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java70
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java13
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java11
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java97
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java37
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java47
-rw-r--r--services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java27
-rw-r--r--services/core/java/com/android/server/graphics/fonts/FontManagerService.java88
-rw-r--r--services/core/java/com/android/server/hdmi/CecMessageBuffer.java103
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecConfig.java134
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java75
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java15
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java22
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java111
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java20
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java117
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java212
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java135
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java124
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java45
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java39
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java14
-rw-r--r--services/core/java/com/android/server/tv/TEST_MAPPING7
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputManagerService.java11
-rw-r--r--services/core/java/com/android/server/utils/Snappable.java35
-rw-r--r--services/core/java/com/android/server/utils/Snapshots.java133
-rw-r--r--services/core/java/com/android/server/utils/WatchableImpl.java33
-rw-r--r--services/core/java/com/android/server/utils/WatchedArrayMap.java43
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseArray.java42
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java47
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java169
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java23
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java5
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java10
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicy.java4
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java18
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java236
-rw-r--r--services/core/java/com/android/server/wm/RootDisplayArea.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java28
-rw-r--r--services/core/jni/Android.bp2
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp20
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java45
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java82
-rw-r--r--services/java/com/android/server/SystemServer.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java111
-rw-r--r--services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java74
-rw-r--r--services/tests/servicestests/src/com/android/server/utils/WatchableTester.java87
-rw-r--r--services/tests/servicestests/src/com/android/server/utils/WatcherTest.java375
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java16
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java47
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java79
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java75
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java18
-rw-r--r--telecomm/java/android/telecom/BluetoothCallQualityReport.java256
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java13
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java12
-rw-r--r--telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl2
-rw-r--r--telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java4
-rw-r--r--telephony/java/android/telephony/ims/feature/MmTelFeature.java15
-rw-r--r--telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt2
-rw-r--r--tests/Input/Android.bp1
-rw-r--r--tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt78
-rw-r--r--tests/StagedInstallTest/Android.bp1
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java14
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java117
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java105
-rw-r--r--wifi/Android.bp2
-rw-r--r--wifi/tests/Android.bp3
288 files changed, 7104 insertions, 2938 deletions
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 6aad82fda915..d22549738e74 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -40,6 +40,7 @@ cc_defaults {
"src/external/StatsPullerManager.cpp",
"src/external/TrainInfoPuller.cpp",
"src/FieldValue.cpp",
+ "src/flags/flags.cpp",
"src/guardrail/StatsdStats.cpp",
"src/hash.cpp",
"src/HashableDimensionKey.cpp",
@@ -92,6 +93,7 @@ cc_defaults {
"libstatslog_statsd",
"libsysutils",
"libutils",
+ "server_configurable_flags",
"statsd-aidl-ndk_platform",
],
shared_libs: [
@@ -265,6 +267,7 @@ cc_test {
"tests/e2e/Anomaly_duration_sum_e2e_test.cpp",
"tests/e2e/Attribution_e2e_test.cpp",
"tests/e2e/ConfigTtl_e2e_test.cpp",
+ "tests/e2e/ConfigUpdate_e2e_ab_test.cpp",
"tests/e2e/ConfigUpdate_e2e_test.cpp",
"tests/e2e/CountMetric_e2e_test.cpp",
"tests/e2e/DurationMetric_e2e_test.cpp",
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 6eff639aca92..c5d9f54dbf38 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -24,12 +24,13 @@
#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
#include <frameworks/base/cmds/statsd/src/experiment_ids.pb.h>
+#include "StatsService.h"
#include "android-base/stringprintf.h"
#include "external/StatsPullerManager.h"
+#include "flags/flags.h"
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "metrics/CountMetricProducer.h"
-#include "StatsService.h"
#include "state/StateManager.h"
#include "stats_log_util.h"
#include "stats_util.h"
@@ -520,9 +521,10 @@ void StatsLogProcessor::GetActiveConfigsLocked(const int uid, vector<int64_t>& o
}
void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
- const StatsdConfig& config, bool modularUpdate) {
+ const StatsdConfig& config) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
WriteDataToDiskLocked(key, timestampNs, CONFIG_UPDATED, NO_TIME_CONSTRAINTS);
+ bool modularUpdate = getFlagBool(PARTIAL_CONFIG_UPDATE_FLAG, "false");
OnConfigUpdatedLocked(timestampNs, key, config, modularUpdate);
}
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 2af277ad1e5b..a320b2f3ba5c 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -48,7 +48,7 @@ public:
void OnLogEvent(LogEvent* event);
void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
- const StatsdConfig& config, bool modularUpdate = false);
+ const StatsdConfig& config);
void OnConfigRemoved(const ConfigKey& key);
size_t GetMetricsSize(const ConfigKey& key) const;
@@ -338,9 +338,9 @@ private:
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
- FRIEND_TEST(ConfigUpdateE2eTest, TestHashStrings);
- FRIEND_TEST(ConfigUpdateE2eTest, TestUidMapVersionStringInstaller);
- FRIEND_TEST(ConfigUpdateE2eTest, TestConfigTtl);
+ FRIEND_TEST(ConfigUpdateE2eAbTest, TestHashStrings);
+ FRIEND_TEST(ConfigUpdateE2eAbTest, TestUidMapVersionStringInstaller);
+ FRIEND_TEST(ConfigUpdateE2eAbTest, TestConfigTtl);
FRIEND_TEST(CountMetricE2eTest, TestInitialConditionChanges);
FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 672d61c82268..d355146c13ef 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -85,16 +85,14 @@ public:
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensions) const override;
- void getTrueSlicedDimensions(
- const std::vector<sp<ConditionTracker>>& allConditions,
- std::set<HashableDimensionKey>* dimensions) const override {
+ const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(
+ const std::vector<sp<ConditionTracker>>& allConditions) const override {
if (mSlicedChildren.size() == 1) {
- return allConditions[mSlicedChildren.front()]->getTrueSlicedDimensions(
- allConditions, dimensions);
+ return allConditions[mSlicedChildren.front()]->getSlicedDimensionMap(allConditions);
}
+ return nullptr;
}
-
private:
LogicalOperation mLogicalOperation;
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 5a6b8cf334eb..7af022a5677a 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -135,9 +135,8 @@ public:
return mProtoHash;
}
- virtual void getTrueSlicedDimensions(
- const std::vector<sp<ConditionTracker>>& allConditions,
- std::set<HashableDimensionKey>* dimensions) const = 0;
+ virtual const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(
+ const std::vector<sp<ConditionTracker>>& allConditions) const = 0;
virtual bool IsChangedDimensionTrackable() const = 0;
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
index 892647910d9f..43db94cfa47d 100644
--- a/cmds/statsd/src/condition/ConditionWizard.h
+++ b/cmds/statsd/src/condition/ConditionWizard.h
@@ -53,9 +53,9 @@ public:
ConditionState getUnSlicedPartConditionState(const int index) {
return mAllConditions[index]->getUnSlicedPartConditionState();
}
- void getTrueSlicedDimensions(const int index,
- std::set<HashableDimensionKey>* trueDimensions) const {
- return mAllConditions[index]->getTrueSlicedDimensions(mAllConditions, trueDimensions);
+
+ const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(const int index) const {
+ return mAllConditions[index]->getSlicedDimensionMap(mAllConditions);
}
private:
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index 7a8b40108448..2fbc8a7b4ea8 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -74,14 +74,9 @@ public:
}
}
- void getTrueSlicedDimensions(
- const std::vector<sp<ConditionTracker>>& allConditions,
- std::set<HashableDimensionKey>* dimensions) const override {
- for (const auto& itr : mSlicedConditionState) {
- if (itr.second > 0) {
- dimensions->insert(itr.first);
- }
- }
+ const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(
+ const std::vector<sp<ConditionTracker>>& allConditions) const override {
+ return &mSlicedConditionState;
}
bool IsChangedDimensionTrackable() const override { return true; }
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
index 3d301379f359..dcd5e52feefd 100644
--- a/cmds/statsd/src/config/ConfigListener.h
+++ b/cmds/statsd/src/config/ConfigListener.h
@@ -39,7 +39,7 @@ public:
* A configuration was added or updated.
*/
virtual void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
- const StatsdConfig& config, bool modularUpdate = false) = 0;
+ const StatsdConfig& config) = 0;
/**
* A configuration was removed.
diff --git a/cmds/statsd/src/flags/flags.cpp b/cmds/statsd/src/flags/flags.cpp
new file mode 100644
index 000000000000..e9fceda72b6d
--- /dev/null
+++ b/cmds/statsd/src/flags/flags.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include "flags.h"
+
+#include <server_configurable_flags/get_flags.h>
+
+using server_configurable_flags::GetServerConfigurableFlag;
+using std::string;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+string getFlagString(const string& flagName, const string& defaultValue) {
+ return GetServerConfigurableFlag(STATSD_NATIVE_NAMESPACE, flagName, defaultValue);
+}
+
+bool getFlagBool(const string& flagName, const string& defaultValue) {
+ return getFlagString(flagName, defaultValue) == "true";
+}
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/flags/flags.h b/cmds/statsd/src/flags/flags.h
new file mode 100644
index 000000000000..213e1a48b074
--- /dev/null
+++ b/cmds/statsd/src/flags/flags.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+const std::string STATSD_NATIVE_NAMESPACE = "statsd_native";
+
+const std::string PARTIAL_CONFIG_UPDATE_FLAG = "partial_config_update";
+
+std::string getFlagString(const std::string& flagName, const std::string& defaultValue);
+
+// Returns true IFF flagName has a value of "true".
+bool getFlagBool(const std::string& flagName, const std::string& defaultValue);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 8869241ab8aa..001ad36134e9 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -67,8 +67,8 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
DurationMetricProducer::DurationMetricProducer(
const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
- const vector<ConditionState>& initialConditionCache, const int startIndex,
- const int stopIndex, const int stopAllIndex, const bool nesting,
+ const vector<ConditionState>& initialConditionCache, const int whatIndex,
+ const int startIndex, const int stopIndex, const int stopAllIndex, const bool nesting,
const sp<ConditionWizard>& wizard, const uint64_t protoHash,
const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
@@ -107,6 +107,12 @@ DurationMetricProducer::DurationMetricProducer(
ALOGE("Position ANY in dimension_in_what not supported.");
}
+ // Dimensions in what must be subset of internal dimensions
+ if (!subsetDimensions(mDimensionsInWhat, mInternalDimensions)) {
+ ALOGE("Dimensions in what must be a subset of the internal dimensions");
+ mValid = false;
+ }
+
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
if (metric.links().size() > 0) {
@@ -115,6 +121,10 @@ DurationMetricProducer::DurationMetricProducer(
mc.conditionId = link.condition();
translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
+ if (!subsetDimensions(mc.metricFields, mInternalDimensions)) {
+ ALOGE(("Condition links must be a subset of the internal dimensions"));
+ mValid = false;
+ }
mMetric2ConditionLinks.push_back(mc);
}
mConditionSliced = true;
@@ -126,6 +136,10 @@ DurationMetricProducer::DurationMetricProducer(
ms.stateAtomId = stateLink.state_atom_id();
translateFieldMatcher(stateLink.fields_in_what(), &ms.metricFields);
translateFieldMatcher(stateLink.fields_in_state(), &ms.stateFields);
+ if (!subsetDimensions(ms.metricFields, mInternalDimensions)) {
+ ALOGE(("State links must be a subset of the dimensions in what internal dimensions"));
+ mValid = false;
+ }
mMetric2StateLinks.push_back(ms);
}
@@ -140,6 +154,8 @@ DurationMetricProducer::DurationMetricProducer(
mCurrentBucketStartTimeNs = startTimeNs;
VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mTimeBaseNs);
+
+ initTrueDimensions(whatIndex, startTimeNs);
}
DurationMetricProducer::~DurationMetricProducer() {
@@ -224,6 +240,23 @@ bool DurationMetricProducer::onConfigUpdatedLocked(
return true;
}
+void DurationMetricProducer::initTrueDimensions(const int whatIndex, const int64_t startTimeNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ // Currently whatIndex will only be -1 in tests. In the future, we might want to avoid creating
+ // a ConditionTracker if the condition is only used in the "what" of a duration metric. In that
+ // scenario, -1 can also be passed.
+ if (whatIndex == -1) {
+ return;
+ }
+ const map<HashableDimensionKey, int>* slicedWhatMap = mWizard->getSlicedDimensionMap(whatIndex);
+ for (const auto& [internalDimKey, count] : *slicedWhatMap) {
+ for (int i = 0; i < count; i++) {
+ // Fake start events.
+ handleMatchedLogEventValuesLocked(mStartIndex, internalDimKey.getValues(), startTimeNs);
+ }
+ }
+}
+
sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) {
std::lock_guard<std::mutex> lock(mMutex);
@@ -330,14 +363,14 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio
// state based on the new unsliced condition state.
if (dimensionsChangedToTrue == nullptr || dimensionsChangedToFalse == nullptr ||
(dimensionsChangedToTrue->empty() && dimensionsChangedToFalse->empty())) {
- std::set<HashableDimensionKey> trueConditionDimensions;
- mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, &trueConditionDimensions);
+ const map<HashableDimensionKey, int>* slicedConditionMap =
+ mWizard->getSlicedDimensionMap(mConditionTrackerIndex);
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
HashableDimensionKey linkedConditionDimensionKey;
getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
&linkedConditionDimensionKey);
- if (trueConditionDimensions.find(linkedConditionDimensionKey) !=
- trueConditionDimensions.end()) {
+ const auto& slicedConditionIt = slicedConditionMap->find(linkedConditionDimensionKey);
+ if (slicedConditionIt != slicedConditionMap->end() && slicedConditionIt->second > 0) {
whatIt.second->onConditionChanged(currentUnSlicedPartCondition, eventTime);
}
}
@@ -595,8 +628,9 @@ bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey
}
void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKeys,
- bool condition, const LogEvent& event) {
+ const ConditionKey& conditionKeys, bool condition,
+ const int64_t eventTimeNs,
+ const vector<FieldValue>& eventValues) {
const auto& whatKey = eventKey.getDimensionKeyInWhat();
auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
@@ -608,20 +642,17 @@ void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey
auto it = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (mUseWhatDimensionAsInternalDimension) {
- it->second->noteStart(whatKey, condition, event.GetElapsedTimestampNs(), conditionKeys);
+ it->second->noteStart(whatKey, condition, eventTimeNs, conditionKeys);
return;
}
if (mInternalDimensions.empty()) {
- it->second->noteStart(DEFAULT_DIMENSION_KEY, condition, event.GetElapsedTimestampNs(),
- conditionKeys);
+ it->second->noteStart(DEFAULT_DIMENSION_KEY, condition, eventTimeNs, conditionKeys);
} else {
HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY;
- filterValues(mInternalDimensions, event.getValues(), &dimensionKey);
- it->second->noteStart(dimensionKey, condition, event.GetElapsedTimestampNs(),
- conditionKeys);
+ filterValues(mInternalDimensions, eventValues, &dimensionKey);
+ it->second->noteStart(dimensionKey, condition, eventTimeNs, conditionKeys);
}
-
}
void DurationMetricProducer::onMatchedLogEventInternalLocked(
@@ -633,26 +664,32 @@ void DurationMetricProducer::onMatchedLogEventInternalLocked(
void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
const LogEvent& event) {
- int64_t eventTimeNs = event.GetElapsedTimestampNs();
+ handleMatchedLogEventValuesLocked(matcherIndex, event.getValues(),
+ event.GetElapsedTimestampNs());
+}
+
+void DurationMetricProducer::handleMatchedLogEventValuesLocked(const size_t matcherIndex,
+ const vector<FieldValue>& values,
+ const int64_t eventTimeNs) {
if (eventTimeNs < mTimeBaseNs) {
return;
}
if (mIsActive) {
- flushIfNeededLocked(event.GetElapsedTimestampNs());
+ flushIfNeededLocked(eventTimeNs);
}
// Handles Stopall events.
if ((int)matcherIndex == mStopAllIndex) {
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- whatIt.second->noteStopAll(event.GetElapsedTimestampNs());
+ whatIt.second->noteStopAll(eventTimeNs);
}
return;
}
HashableDimensionKey dimensionInWhat = DEFAULT_DIMENSION_KEY;
if (!mDimensionsInWhat.empty()) {
- filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
+ filterValues(mDimensionsInWhat, values, &dimensionInWhat);
}
// Stores atom id to primary key pairs for each state atom that the metric is
@@ -663,8 +700,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
// field values from the log event. These values will form a primary key
// that will be used to query StateTracker for the correct state value.
for (const auto& stateLink : mMetric2StateLinks) {
- getDimensionForState(event.getValues(), stateLink,
- &statePrimaryKeys[stateLink.stateAtomId]);
+ getDimensionForState(values, stateLink, &statePrimaryKeys[stateLink.stateAtomId]);
}
// For each sliced state, query StateTracker for the state value using
@@ -695,19 +731,19 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
if (mUseWhatDimensionAsInternalDimension) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- whatIt->second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
+ whatIt->second->noteStop(dimensionInWhat, eventTimeNs, false);
}
return;
}
HashableDimensionKey internalDimensionKey = DEFAULT_DIMENSION_KEY;
if (!mInternalDimensions.empty()) {
- filterValues(mInternalDimensions, event.getValues(), &internalDimensionKey);
+ filterValues(mInternalDimensions, values, &internalDimensionKey);
}
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- whatIt->second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(), false);
+ whatIt->second->noteStop(internalDimensionKey, eventTimeNs, false);
}
return;
}
@@ -716,7 +752,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
ConditionKey conditionKey;
if (mConditionSliced) {
for (const auto& link : mMetric2ConditionLinks) {
- getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
+ getDimensionForCondition(values, link, &conditionKey[link.conditionId]);
}
auto conditionState =
@@ -731,7 +767,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
condition = condition && mIsActive;
handleStartEvent(MetricDimensionKey(dimensionInWhat, stateValuesKey), conditionKey, condition,
- event);
+ eventTimeNs, values);
}
size_t DurationMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 5feb09fc1c98..9fb586f7262f 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -40,8 +40,8 @@ class DurationMetricProducer : public MetricProducer {
public:
DurationMetricProducer(
const ConfigKey& key, const DurationMetric& durationMetric, const int conditionIndex,
- const vector<ConditionState>& initialConditionCache, const int startIndex,
- const int stopIndex, const int stopAllIndex, const bool nesting,
+ const vector<ConditionState>& initialConditionCache, const int whatIndex,
+ const int startIndex, const int stopIndex, const int stopAllIndex, const bool nesting,
const sp<ConditionWizard>& wizard, const uint64_t protoHash,
const FieldMatcher& internalDimensions, const int64_t timeBaseNs,
const int64_t startTimeNs,
@@ -74,8 +74,15 @@ protected:
const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
private:
+ // Initializes true dimensions of the 'what' predicate. Only to be called during initialization.
+ void initTrueDimensions(const int whatIndex, const int64_t startTimeNs);
+
+ void handleMatchedLogEventValuesLocked(const size_t matcherIndex,
+ const std::vector<FieldValue>& values,
+ const int64_t eventTimeNs);
void handleStartEvent(const MetricDimensionKey& eventKey, const ConditionKey& conditionKeys,
- bool condition, const LogEvent& event);
+ bool condition, const int64_t eventTimeNs,
+ const vector<FieldValue>& eventValues);
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 5b321a0e3d60..c68e61e78f2e 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -56,6 +56,7 @@ MetricProducer::MetricProducer(
: mMetricId(metricId),
mProtoHash(protoHash),
mConfigKey(key),
+ mValid(true),
mTimeBaseNs(timeBaseNs),
mCurrentBucketStartTimeNs(timeBaseNs),
mCurrentBucketNum(0),
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 0dc8edae8056..7a1c008bd134 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -336,6 +336,10 @@ public:
return mSlicedStateAtoms;
}
+ inline bool isValid() const {
+ return mValid;
+ }
+
/* Adds an AnomalyTracker and returns it. */
virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
const sp<AlarmMonitor>& anomalyAlarmMonitor) {
@@ -468,6 +472,8 @@ protected:
const ConfigKey mConfigKey;
+ bool mValid;
+
// The time when this metric producer was first created. The end time for the current bucket
// can be computed from this based on mCurrentBucketNum.
int64_t mTimeBaseNs;
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 3c9ecdb46fd2..0e563710d56f 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -334,7 +334,7 @@ private:
FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
- FRIEND_TEST(ConfigUpdateE2eTest, TestConfigTtl);
+ FRIEND_TEST(ConfigUpdateE2eAbTest, TestConfigTtl);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations);
diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
index 4474df4346cf..bfa409cb8a64 100644
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
@@ -450,7 +450,8 @@ optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
return nullopt;
}
- const Predicate& durationWhat = config.predicate(what_it->second);
+ const int whatIndex = what_it->second;
+ const Predicate& durationWhat = config.predicate(whatIndex);
if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
ALOGE("DurationMetric's \"what\" must be a simple condition");
return nullopt;
@@ -518,6 +519,7 @@ optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
for (const auto& stateLink : metric.state_link()) {
if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) {
+ ALOGW("DurationMetric's MetricStateLinks must be a subset of dimensions in what");
return nullopt;
}
}
@@ -536,10 +538,15 @@ optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
return nullopt;
}
- return {new DurationMetricProducer(
- key, metric, conditionIndex, initialConditionCache, startIndex, stopIndex, stopAllIndex,
- nesting, wizard, metricHash, internalDimensions, timeBaseNs, currentTimeNs,
- eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap)};
+ sp<MetricProducer> producer = new DurationMetricProducer(
+ key, metric, conditionIndex, initialConditionCache, whatIndex, startIndex, stopIndex,
+ stopAllIndex, nesting, wizard, metricHash, internalDimensions, timeBaseNs,
+ currentTimeNs, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
+ stateGroupMap);
+ if (!producer->isValid()) {
+ return nullopt;
+ }
+ return {producer};
}
optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
@@ -677,6 +684,7 @@ optional<sp<MetricProducer>> createValueMetricProducerAndUpdateMetadata(
translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
for (const auto& stateLink : metric.state_link()) {
if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) {
+ ALOGW("ValueMetric's MetricStateLinks must be a subset of the dimensions in what");
return nullopt;
}
}
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index 1d8371638e90..24c8f2b1b2d8 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -44,8 +44,8 @@ static ostream& operator<<(ostream& os, const StatsdConfig& config) {
*/
class MockListener : public ConfigListener {
public:
- MOCK_METHOD4(OnConfigUpdated, void(const int64_t timestampNs, const ConfigKey& key,
- const StatsdConfig& config, bool modularUpdate));
+ MOCK_METHOD3(OnConfigUpdated,
+ void(const int64_t timestampNs, const ConfigKey& key, const StatsdConfig& config));
MOCK_METHOD1(OnConfigRemoved, void(const ConfigKey& key));
};
@@ -90,25 +90,25 @@ TEST(ConfigManagerTest, TestAddUpdateRemove) {
// Add another one
EXPECT_CALL(*(listener.get()),
- OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), StatsdConfigEq(91), _))
+ OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), StatsdConfigEq(91)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config91);
// Update It
EXPECT_CALL(*(listener.get()),
- OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), StatsdConfigEq(92), _))
+ OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), StatsdConfigEq(92)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config92);
// Add one with the same uid but a different name
EXPECT_CALL(*(listener.get()),
- OnConfigUpdated(_, ConfigKeyEq(1, StringToId("yyy")), StatsdConfigEq(93), _))
+ OnConfigUpdated(_, ConfigKeyEq(1, StringToId("yyy")), StatsdConfigEq(93)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("yyy")), config93);
// Add one with the same name but a different uid
EXPECT_CALL(*(listener.get()),
- OnConfigUpdated(_, ConfigKeyEq(2, StringToId("zzz")), StatsdConfigEq(94), _))
+ OnConfigUpdated(_, ConfigKeyEq(2, StringToId("zzz")), StatsdConfigEq(94)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config94);
@@ -143,7 +143,7 @@ TEST(ConfigManagerTest, TestRemoveUid) {
StatsdConfig config;
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _, _, _)).Times(5);
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _, _)).Times(5);
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("xxx"))));
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("yyy"))));
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz"))));
diff --git a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_ab_test.cpp b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_ab_test.cpp
new file mode 100644
index 000000000000..098f284fdc64
--- /dev/null
+++ b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_ab_test.cpp
@@ -0,0 +1,328 @@
+// 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.
+
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <gtest/gtest.h>
+
+#include "flags/flags.h"
+#include "src/StatsLogProcessor.h"
+#include "src/storage/StorageManager.h"
+#include "tests/statsd_test_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+#define STATS_DATA_DIR "/data/misc/stats-data"
+
+using android::base::SetProperty;
+using android::base::StringPrintf;
+using namespace std;
+
+namespace {
+
+StatsdConfig CreateSimpleConfig() {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_STATSD");
+ config.set_hash_strings_in_metric_report(false);
+
+ *config.add_atom_matcher() = CreateBatteryStateUsbMatcher();
+ // Simple count metric so the config isn't empty.
+ CountMetric* countMetric1 = config.add_count_metric();
+ countMetric1->set_id(StringToId("Count1"));
+ countMetric1->set_what(config.atom_matcher(0).id());
+ countMetric1->set_bucket(FIVE_MINUTES);
+ return config;
+}
+} // namespace
+
+// Setup for parameterized tests.
+class ConfigUpdateE2eAbTest : public TestWithParam<bool> {
+private:
+ string originalFlagValue;
+
+public:
+ void SetUp() override {
+ originalFlagValue = getFlagBool(PARTIAL_CONFIG_UPDATE_FLAG, "");
+ string rawFlagName =
+ StringPrintf("persist.device_config.%s.%s", STATSD_NATIVE_NAMESPACE.c_str(),
+ PARTIAL_CONFIG_UPDATE_FLAG.c_str());
+ SetProperty(rawFlagName, GetParam() ? "true" : "false");
+ }
+
+ void TearDown() override {
+ string rawFlagName =
+ StringPrintf("persist.device_config.%s.%s", STATSD_NATIVE_NAMESPACE.c_str(),
+ PARTIAL_CONFIG_UPDATE_FLAG.c_str());
+ SetProperty(rawFlagName, originalFlagValue);
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(ConfigUpdateE2eAbTest, ConfigUpdateE2eAbTest, testing::Bool());
+
+TEST_P(ConfigUpdateE2eAbTest, TestUidMapVersionStringInstaller) {
+ sp<UidMap> uidMap = new UidMap();
+ vector<int32_t> uids({1000});
+ vector<int64_t> versions({1});
+ vector<String16> apps({String16("app1")});
+ vector<String16> versionStrings({String16("v1")});
+ vector<String16> installers({String16("installer1")});
+ uidMap->updateMap(1, uids, versions, versionStrings, apps, installers);
+
+ StatsdConfig config = CreateSimpleConfig();
+ config.set_version_strings_in_metric_report(true);
+ config.set_installer_in_metric_report(false);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+
+ // Now update.
+ config.set_version_strings_in_metric_report(false);
+ config.set_installer_in_metric_report(true);
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
+ EXPECT_TRUE(metricsManager->isConfigValid());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ // First report is written to disk when the update happens.
+ ASSERT_EQ(reports.reports_size(), 2);
+ UidMapping uidMapping = reports.reports(1).uid_map();
+ ASSERT_EQ(uidMapping.snapshots_size(), 1);
+ ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
+ EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string());
+ EXPECT_EQ(uidMapping.snapshots(0).package_info(0).installer(), "installer1");
+}
+
+TEST_P(ConfigUpdateE2eAbTest, TestHashStrings) {
+ sp<UidMap> uidMap = new UidMap();
+ vector<int32_t> uids({1000});
+ vector<int64_t> versions({1});
+ vector<String16> apps({String16("app1")});
+ vector<String16> versionStrings({String16("v1")});
+ vector<String16> installers({String16("installer1")});
+ uidMap->updateMap(1, uids, versions, versionStrings, apps, installers);
+
+ StatsdConfig config = CreateSimpleConfig();
+ config.set_version_strings_in_metric_report(true);
+ config.set_hash_strings_in_metric_report(true);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+
+ // Now update.
+ config.set_hash_strings_in_metric_report(false);
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
+ EXPECT_TRUE(metricsManager->isConfigValid());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ // First report is written to disk when the update happens.
+ ASSERT_EQ(reports.reports_size(), 2);
+ UidMapping uidMapping = reports.reports(1).uid_map();
+ ASSERT_EQ(uidMapping.snapshots_size(), 1);
+ ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
+ EXPECT_TRUE(uidMapping.snapshots(0).package_info(0).has_version_string());
+ EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string_hash());
+}
+
+TEST_P(ConfigUpdateE2eAbTest, TestAnnotations) {
+ StatsdConfig config = CreateSimpleConfig();
+ StatsdConfig_Annotation* annotation = config.add_annotation();
+ annotation->set_field_int64(11);
+ annotation->set_field_int32(1);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+
+ // Now update
+ config.clear_annotation();
+ annotation = config.add_annotation();
+ annotation->set_field_int64(22);
+ annotation->set_field_int32(2);
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ // First report is written to disk when the update happens.
+ ASSERT_EQ(reports.reports_size(), 2);
+ ConfigMetricsReport report = reports.reports(1);
+ EXPECT_EQ(report.annotation_size(), 1);
+ EXPECT_EQ(report.annotation(0).field_int64(), 22);
+ EXPECT_EQ(report.annotation(0).field_int32(), 2);
+}
+
+TEST_P(ConfigUpdateE2eAbTest, TestPersistLocally) {
+ StatsdConfig config = CreateSimpleConfig();
+ config.set_persist_locally(false);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 1);
+ // Number of reports should still be 1 since persist_locally is false.
+ reports.Clear();
+ buffer.clear();
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 1);
+
+ // Now update.
+ config.set_persist_locally(true);
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
+
+ // Should get 2: 1 in memory + 1 on disk. Both should be saved on disk.
+ reports.Clear();
+ buffer.clear();
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 2);
+ // Should get 3, 2 on disk + 1 in memory.
+ reports.Clear();
+ buffer.clear();
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 3);
+ string suffix = StringPrintf("%d_%lld", cfgKey.GetUid(), (long long)cfgKey.GetId());
+ StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, suffix.c_str());
+ string historySuffix =
+ StringPrintf("%d_%lld_history", cfgKey.GetUid(), (long long)cfgKey.GetId());
+ StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, historySuffix.c_str());
+}
+
+TEST_P(ConfigUpdateE2eAbTest, TestNoReportMetrics) {
+ StatsdConfig config = CreateSimpleConfig();
+ // Second simple count metric.
+ CountMetric* countMetric = config.add_count_metric();
+ countMetric->set_id(StringToId("Count2"));
+ countMetric->set_what(config.atom_matcher(0).id());
+ countMetric->set_bucket(FIVE_MINUTES);
+ config.add_no_report_metric(config.count_metric(0).id());
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+
+ // Now update.
+ config.clear_no_report_metric();
+ config.add_no_report_metric(config.count_metric(1).id());
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ // First report is written to disk when the update happens.
+ ASSERT_EQ(reports.reports_size(), 2);
+ // First report (before update) has the first count metric.
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).metric_id(), config.count_metric(1).id());
+ // Second report (after update) has the first count metric.
+ ASSERT_EQ(reports.reports(1).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(1).metrics(0).metric_id(), config.count_metric(0).id());
+}
+
+TEST_P(ConfigUpdateE2eAbTest, TestAtomsAllowedFromAnyUid) {
+ StatsdConfig config = CreateSimpleConfig();
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+ // Uses AID_ROOT, which isn't in allowed log sources.
+ unique_ptr<LogEvent> event = CreateBatteryStateChangedEvent(
+ baseTimeNs + 2, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
+ processor->OnLogEvent(event.get());
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, true, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 1);
+ // Check the metric and make sure it has 0 count.
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_FALSE(reports.reports(0).metrics(0).has_count_metrics());
+
+ // Now update. Allow plugged state to be logged from any uid, so the atom will be counted.
+ config.add_whitelisted_atom_ids(util::PLUGGED_STATE_CHANGED);
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
+ unique_ptr<LogEvent> event2 = CreateBatteryStateChangedEvent(
+ baseTimeNs + 2000, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
+ processor->OnLogEvent(event.get());
+ reports.Clear();
+ buffer.clear();
+ processor->onDumpReport(cfgKey, baseTimeNs + 3000, true, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 2);
+ // Check the metric and make sure it has 0 count.
+ ASSERT_EQ(reports.reports(1).metrics_size(), 1);
+ EXPECT_TRUE(reports.reports(1).metrics(0).has_count_metrics());
+ ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data_size(), 1);
+ ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
+ EXPECT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
+}
+
+TEST_P(ConfigUpdateE2eAbTest, TestConfigTtl) {
+ StatsdConfig config = CreateSimpleConfig();
+ config.set_ttl_in_seconds(1);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + NS_PER_SEC);
+
+ config.set_ttl_in_seconds(5);
+ processor->OnConfigUpdated(baseTimeNs + 2 * NS_PER_SEC, cfgKey, config);
+ metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + 7 * NS_PER_SEC);
+
+ // Clear the data stored on disk as a result of the update.
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 3 * NS_PER_SEC, false, true, ADB_DUMP, FAST,
+ &buffer);
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp
index e01a0b63a0ca..94b778c0e0ea 100644
--- a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp
@@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <gtest/gtest.h>
-#include <thread> // std::this_thread::sleep_for
-
-#include "android-base/stringprintf.h"
+#include "flags/flags.h"
#include "src/StatsLogProcessor.h"
#include "src/storage/StorageManager.h"
#include "tests/statsd_test_util.h"
@@ -26,276 +26,327 @@ namespace os {
namespace statsd {
#ifdef __ANDROID__
-#define STATS_DATA_DIR "/data/misc/stats-data"
+
+using android::base::SetProperty;
using android::base::StringPrintf;
+using namespace std;
+// Tests that only run with the partial config update feature turned on.
namespace {
-
-StatsdConfig CreateSimpleConfig() {
+// Setup for test fixture.
+class ConfigUpdateE2eTest : public ::testing::Test {
+private:
+ string originalFlagValue;
+public:
+ void SetUp() override {
+ originalFlagValue = getFlagBool(PARTIAL_CONFIG_UPDATE_FLAG, "");
+ string rawFlagName =
+ StringPrintf("persist.device_config.%s.%s", STATSD_NATIVE_NAMESPACE.c_str(),
+ PARTIAL_CONFIG_UPDATE_FLAG.c_str());
+ SetProperty(rawFlagName, "true");
+ }
+
+ void TearDown() override {
+ string rawFlagName =
+ StringPrintf("persist.device_config.%s.%s", STATSD_NATIVE_NAMESPACE.c_str(),
+ PARTIAL_CONFIG_UPDATE_FLAG.c_str());
+ SetProperty(rawFlagName, originalFlagValue);
+ }
+};
+} // Anonymous namespace.
+
+TEST_F(ConfigUpdateE2eTest, TestNewDurationExistingWhat) {
StatsdConfig config;
- config.add_allowed_log_source("AID_STATSD");
- config.set_hash_strings_in_metric_report(false);
-
- *config.add_atom_matcher() = CreateBatteryStateUsbMatcher();
- // Simple count metric so the config isn't empty.
- CountMetric* countMetric1 = config.add_count_metric();
- countMetric1->set_id(StringToId("Count1"));
- countMetric1->set_what(config.atom_matcher(0).id());
- countMetric1->set_bucket(FIVE_MINUTES);
- return config;
-}
-} // namespace
-
-// Setup for parameterized tests.
-class ConfigUpdateE2eTest : public TestWithParam<bool> {};
-
-INSTANTIATE_TEST_SUITE_P(ConfigUpdateE2eTest, ConfigUpdateE2eTest, testing::Bool());
-
-TEST_P(ConfigUpdateE2eTest, TestUidMapVersionStringInstaller) {
- sp<UidMap> uidMap = new UidMap();
- vector<int32_t> uids({1000});
- vector<int64_t> versions({1});
- vector<String16> apps({String16("app1")});
- vector<String16> versionStrings({String16("v1")});
- vector<String16> installers({String16("installer1")});
- uidMap->updateMap(1, uids, versions, versionStrings, apps, installers);
+ config.add_allowed_log_source("AID_ROOT");
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
- StatsdConfig config = CreateSimpleConfig();
- config.set_version_strings_in_metric_report(true);
- config.set_installer_in_metric_report(false);
- int64_t baseTimeNs = getElapsedRealtimeNs();
+ Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ *config.add_predicate() = holdingWakelockPredicate;
- ConfigKey cfgKey(0, 12345);
+ ConfigKey key(123, 987);
+ uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(FIVE_MINUTES) * 1000000LL;
sp<StatsLogProcessor> processor =
- CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
- EXPECT_TRUE(metricsManager->isConfigValid());
-
- // Now update.
- config.set_version_strings_in_metric_report(false);
- config.set_installer_in_metric_report(true);
- processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
- EXPECT_TRUE(metricsManager->isConfigValid());
+ CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
+
+ int app1Uid = 123;
+ vector<int> attributionUids1 = {app1Uid};
+ vector<string> attributionTags1 = {"App1"};
+ // Create a wakelock acquire, causing the condition to be true.
+ unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
+ attributionUids1, attributionTags1,
+ "wl1"); // 0:10
+ processor->OnLogEvent(event.get());
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- // First report is written to disk when the update happens.
- ASSERT_EQ(reports.reports_size(), 2);
- UidMapping uidMapping = reports.reports(1).uid_map();
- ASSERT_EQ(uidMapping.snapshots_size(), 1);
- ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
- EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string());
- EXPECT_EQ(uidMapping.snapshots(0).package_info(0).installer(), "installer1");
-}
+ // Add metric.
+ DurationMetric* durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ durationMetric->set_bucket(FIVE_MINUTES);
-TEST_P(ConfigUpdateE2eTest, TestHashStrings) {
- sp<UidMap> uidMap = new UidMap();
- vector<int32_t> uids({1000});
- vector<int64_t> versions({1});
- vector<String16> apps({String16("app1")});
- vector<String16> versionStrings({String16("v1")});
- vector<String16> installers({String16("installer1")});
- uidMap->updateMap(1, uids, versions, versionStrings, apps, installers);
-
- StatsdConfig config = CreateSimpleConfig();
- config.set_version_strings_in_metric_report(true);
- config.set_hash_strings_in_metric_report(true);
- int64_t baseTimeNs = getElapsedRealtimeNs();
-
- ConfigKey cfgKey(0, 12345);
- sp<StatsLogProcessor> processor =
- CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
- EXPECT_TRUE(metricsManager->isConfigValid());
-
- // Now update.
- config.set_hash_strings_in_metric_report(false);
- processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
- EXPECT_TRUE(metricsManager->isConfigValid());
+ uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC; // 1:00
+ processor->OnConfigUpdated(updateTimeNs, key, config);
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + 80 * NS_PER_SEC, attributionUids1,
+ attributionTags1,
+ "wl1"); // 1:20
+ processor->OnLogEvent(event.get());
+ uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC; // 1:30
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- // First report is written to disk when the update happens.
- ASSERT_EQ(reports.reports_size(), 2);
- UidMapping uidMapping = reports.reports(1).uid_map();
- ASSERT_EQ(uidMapping.snapshots_size(), 1);
- ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
- EXPECT_TRUE(uidMapping.snapshots(0).package_info(0).has_version_string());
- EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string_hash());
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ StatsLogReport::DurationMetricDataWrapper metricData;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metricData);
+ ASSERT_EQ(metricData.data_size(), 1);
+ DurationMetricData data = metricData.data(0);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+
+ DurationBucketInfo bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.start_bucket_elapsed_nanos(), updateTimeNs);
+ EXPECT_EQ(bucketInfo.end_bucket_elapsed_nanos(), dumpTimeNs);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 20 * NS_PER_SEC);
}
-TEST_P(ConfigUpdateE2eTest, TestAnnotations) {
- StatsdConfig config = CreateSimpleConfig();
- StatsdConfig_Annotation* annotation = config.add_annotation();
- annotation->set_field_int64(11);
- annotation->set_field_int32(1);
- int64_t baseTimeNs = getElapsedRealtimeNs();
- ConfigKey cfgKey(0, 12345);
+TEST_F(ConfigUpdateE2eTest, TestNewDurationExistingWhatSlicedCondition) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT");
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+ Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ // The predicate is dimensioning by first attribution node by uid.
+ *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ Predicate isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+ *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /*uid*/});
+ *config.add_predicate() = isInBackgroundPredicate;
+
+ ConfigKey key(123, 987);
+ uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(FIVE_MINUTES) * 1000000LL;
sp<StatsLogProcessor> processor =
- CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+ CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
+
+ int app1Uid = 123, app2Uid = 456;
+ vector<int> attributionUids1 = {app1Uid};
+ vector<string> attributionTags1 = {"App1"};
+ vector<int> attributionUids2 = {app2Uid};
+ vector<string> attributionTags2 = {"App2"};
+ unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
+ attributionUids1, attributionTags1,
+ "wl1"); // 0:10
+ processor->OnLogEvent(event.get());
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, app1Uid); // 0:22
+ processor->OnLogEvent(event.get());
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 35 * NS_PER_SEC, attributionUids2,
+ attributionTags2,
+ "wl1"); // 0:35
+ processor->OnLogEvent(event.get());
- // Now update
- config.clear_annotation();
- annotation = config.add_annotation();
- annotation->set_field_int64(22);
- annotation->set_field_int32(2);
- processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
+ // Add metric.
+ DurationMetric* durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_condition(isInBackgroundPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ // The metric is dimensioning by first attribution node and only by uid.
+ *durationMetric->mutable_dimensions_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ durationMetric->set_bucket(FIVE_MINUTES);
+ // Links between wakelock state atom and condition of app is in background.
+ auto links = durationMetric->add_links();
+ links->set_condition(isInBackgroundPredicate.id());
+ *links->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_condition() =
+ CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /*uid*/});
+
+ uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC; // 1:00
+ processor->OnConfigUpdated(updateTimeNs, key, config);
+
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 73 * NS_PER_SEC, app2Uid); // 1:13
+ processor->OnLogEvent(event.get());
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + 84 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1"); // 1:24
+ processor->OnLogEvent(event.get());
+ uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC; // 1:30
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- // First report is written to disk when the update happens.
- ASSERT_EQ(reports.reports_size(), 2);
- ConfigMetricsReport report = reports.reports(1);
- EXPECT_EQ(report.annotation_size(), 1);
- EXPECT_EQ(report.annotation(0).field_int64(), 22);
- EXPECT_EQ(report.annotation(0).field_int32(), 2);
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ StatsLogReport::DurationMetricDataWrapper metricData;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metricData);
+ ASSERT_EQ(metricData.data_size(), 2);
+
+ DurationMetricData data = metricData.data(0);
+ ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ app1Uid);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ DurationBucketInfo bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 24 * NS_PER_SEC);
+
+ data = metricData.data(1);
+ ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ app2Uid);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 17 * NS_PER_SEC);
}
-TEST_P(ConfigUpdateE2eTest, TestPersistLocally) {
- StatsdConfig config = CreateSimpleConfig();
- config.set_persist_locally(false);
- int64_t baseTimeNs = getElapsedRealtimeNs();
- ConfigKey cfgKey(0, 12345);
- sp<StatsLogProcessor> processor =
- CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- ASSERT_EQ(reports.reports_size(), 1);
- // Number of reports should still be 1 since persist_locally is false.
- reports.Clear();
- buffer.clear();
- processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- ASSERT_EQ(reports.reports_size(), 1);
+TEST_F(ConfigUpdateE2eTest, TestNewDurationExistingWhatSlicedState) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT");
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
- // Now update.
- config.set_persist_locally(true);
- processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
+ Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ // The predicate is dimensioning by first attribution node by uid.
+ *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *config.add_predicate() = holdingWakelockPredicate;
- // Should get 2: 1 in memory + 1 on disk. Both should be saved on disk.
- reports.Clear();
- buffer.clear();
- processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- ASSERT_EQ(reports.reports_size(), 2);
- // Should get 3, 2 on disk + 1 in memory.
- reports.Clear();
- buffer.clear();
- processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- ASSERT_EQ(reports.reports_size(), 3);
- string suffix = StringPrintf("%d_%lld", cfgKey.GetUid(), (long long)cfgKey.GetId());
- StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, suffix.c_str());
- string historySuffix =
- StringPrintf("%d_%lld_history", cfgKey.GetUid(), (long long)cfgKey.GetId());
- StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, historySuffix.c_str());
-}
+ auto uidProcessState = CreateUidProcessState();
+ *config.add_state() = uidProcessState;
-TEST_P(ConfigUpdateE2eTest, TestNoReportMetrics) {
- StatsdConfig config = CreateSimpleConfig();
- // Second simple count metric.
+ // Count metric. We don't care about this one. Only use it so the StateTracker gets persisted.
CountMetric* countMetric = config.add_count_metric();
- countMetric->set_id(StringToId("Count2"));
+ countMetric->set_id(StringToId("Tmp"));
countMetric->set_what(config.atom_matcher(0).id());
+ countMetric->add_slice_by_state(uidProcessState.id());
+ // The metric is dimensioning by first attribution node and only by uid.
+ *countMetric->mutable_dimensions_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
countMetric->set_bucket(FIVE_MINUTES);
- config.add_no_report_metric(config.count_metric(0).id());
- int64_t baseTimeNs = getElapsedRealtimeNs();
- ConfigKey cfgKey(0, 12345);
+ auto stateLink = countMetric->add_state_link();
+ stateLink->set_state_atom_id(util::UID_PROCESS_STATE_CHANGED);
+ *stateLink->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *stateLink->mutable_fields_in_state() =
+ CreateDimensions(util::UID_PROCESS_STATE_CHANGED, {1 /*uid*/});
+ config.add_no_report_metric(countMetric->id());
+
+ ConfigKey key(123, 987);
+ uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(FIVE_MINUTES) * 1000000LL;
sp<StatsLogProcessor> processor =
- CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
-
- // Now update.
- config.clear_no_report_metric();
- config.add_no_report_metric(config.count_metric(1).id());
- processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- // First report is written to disk when the update happens.
- ASSERT_EQ(reports.reports_size(), 2);
- // First report (before update) has the first count metric.
- ASSERT_EQ(reports.reports(0).metrics_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).metric_id(), config.count_metric(1).id());
- // Second report (after update) has the first count metric.
- ASSERT_EQ(reports.reports(1).metrics_size(), 1);
- EXPECT_EQ(reports.reports(1).metrics(0).metric_id(), config.count_metric(0).id());
-}
+ CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
+
+ int app1Uid = 123, app2Uid = 456;
+ vector<int> attributionUids1 = {app1Uid};
+ vector<string> attributionTags1 = {"App1"};
+ vector<int> attributionUids2 = {app2Uid};
+ vector<string> attributionTags2 = {"App2"};
+ unique_ptr<LogEvent> event = CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 10 * NS_PER_SEC, app1Uid,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND); // 0:10
+ processor->OnLogEvent(event.get());
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 22 * NS_PER_SEC, attributionUids1,
+ attributionTags1,
+ "wl1"); // 0:22
+ processor->OnLogEvent(event.get());
+ event = CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 30 * NS_PER_SEC, app2Uid,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND); // 0:30
+ processor->OnLogEvent(event.get());
-TEST_P(ConfigUpdateE2eTest, TestAtomsAllowedFromAnyUid) {
- StatsdConfig config = CreateSimpleConfig();
- int64_t baseTimeNs = getElapsedRealtimeNs();
- ConfigKey cfgKey(0, 12345);
- sp<StatsLogProcessor> processor =
- CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
- // Uses AID_ROOT, which isn't in allowed log sources.
- unique_ptr<LogEvent> event = CreateBatteryStateChangedEvent(
- baseTimeNs + 2, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
+ // Add metric.
+ DurationMetric* durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->add_slice_by_state(uidProcessState.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ // The metric is dimensioning by first attribution node and only by uid.
+ *durationMetric->mutable_dimensions_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ durationMetric->set_bucket(FIVE_MINUTES);
+ // Links between wakelock state atom and condition of app is in background.
+ stateLink = durationMetric->add_state_link();
+ stateLink->set_state_atom_id(util::UID_PROCESS_STATE_CHANGED);
+ *stateLink->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *stateLink->mutable_fields_in_state() =
+ CreateDimensions(util::UID_PROCESS_STATE_CHANGED, {1 /*uid*/});
+
+ uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC; // 1:00
+ processor->OnConfigUpdated(updateTimeNs, key, config);
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 72 * NS_PER_SEC, attributionUids2,
+ attributionTags2,
+ "wl1"); // 1:13
processor->OnLogEvent(event.get());
+ event = CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 75 * NS_PER_SEC, app1Uid,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND); // 1:15
+ processor->OnLogEvent(event.get());
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + 84 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1"); // 1:24
+ processor->OnLogEvent(event.get());
+
+ uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC; // 1:30
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, baseTimeNs + 1001, true, true, ADB_DUMP, FAST, &buffer);
+ processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
ASSERT_EQ(reports.reports_size(), 1);
- // Check the metric and make sure it has 0 count.
ASSERT_EQ(reports.reports(0).metrics_size(), 1);
- EXPECT_FALSE(reports.reports(0).metrics(0).has_count_metrics());
-
- // Now update. Allow plugged state to be logged from any uid, so the atom will be counted.
- config.add_whitelisted_atom_ids(util::PLUGGED_STATE_CHANGED);
- processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
- unique_ptr<LogEvent> event2 = CreateBatteryStateChangedEvent(
- baseTimeNs + 2000, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
- processor->OnLogEvent(event.get());
- reports.Clear();
- buffer.clear();
- processor->onDumpReport(cfgKey, baseTimeNs + 3000, true, true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- ASSERT_EQ(reports.reports_size(), 2);
- // Check the metric and make sure it has 0 count.
- ASSERT_EQ(reports.reports(1).metrics_size(), 1);
- EXPECT_TRUE(reports.reports(1).metrics(0).has_count_metrics());
- ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data_size(), 1);
- ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
- EXPECT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
-}
-
-TEST_P(ConfigUpdateE2eTest, TestConfigTtl) {
- StatsdConfig config = CreateSimpleConfig();
- config.set_ttl_in_seconds(1);
- int64_t baseTimeNs = getElapsedRealtimeNs();
- ConfigKey cfgKey(0, 12345);
- sp<StatsLogProcessor> processor =
- CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
- EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + NS_PER_SEC);
-
- config.set_ttl_in_seconds(5);
- processor->OnConfigUpdated(baseTimeNs + 2 * NS_PER_SEC, cfgKey, config,
- /*modularUpdate=*/GetParam());
- metricsManager = processor->mMetricsManagers.begin()->second;
- EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + 7 * NS_PER_SEC);
-
- // Clear the data stored on disk as a result of the update.
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, baseTimeNs + 3 * NS_PER_SEC, false, true, ADB_DUMP, FAST,
- &buffer);
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ StatsLogReport::DurationMetricDataWrapper metricData;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metricData);
+ ASSERT_EQ(metricData.data_size(), 3);
+
+ DurationMetricData data = metricData.data(0);
+ ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ app1Uid);
+ ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ DurationBucketInfo bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 15 * NS_PER_SEC);
+
+ data = metricData.data(1);
+ ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ app1Uid);
+ ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 9 * NS_PER_SEC);
+
+ data = metricData.data(2);
+ ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ app2Uid);
+ ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 18 * NS_PER_SEC);
}
#else
diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
index 4efb038e538d..2473c1ca1101 100644
--- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -486,11 +486,11 @@ TEST(DurationMetricE2eTest, TestWithSlicedCondition) {
// Links between wakelock state atom and condition of app is in background.
auto links = durationMetric->add_links();
links->set_condition(isInBackgroundPredicate.id());
- auto dimensionWhat = links->mutable_fields_in_what();
- dimensionWhat->set_field(util::WAKELOCK_STATE_CHANGED);
- dimensionWhat->add_child()->set_field(1); // uid field.
- *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
- util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ auto dimensionCondition = links->mutable_fields_in_condition();
+ dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+ dimensionCondition->add_child()->set_field(1); // uid field.
ConfigKey cfgKey;
uint64_t bucketStartTimeNs = 10000000000;
@@ -591,11 +591,11 @@ TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) {
// Links between wakelock state atom and condition of app is in background.
auto links = durationMetric->add_links();
links->set_condition(isInBackgroundPredicate.id());
- auto dimensionWhat = links->mutable_fields_in_what();
- dimensionWhat->set_field(util::WAKELOCK_STATE_CHANGED);
- dimensionWhat->add_child()->set_field(1); // uid field.
- *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
- util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ auto dimensionCondition = links->mutable_fields_in_condition();
+ dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+ dimensionCondition->add_child()->set_field(1); // uid field.
auto metric_activation1 = config.add_metric_activation();
metric_activation1->set_metric_id(durationMetric->id());
@@ -1228,6 +1228,9 @@ TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset) {
*config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ *(holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions()) =
+ CreateAttributionUidAndOtherDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST},
+ {3 /* tag */});
*config.add_predicate() = holdingWakelockPredicate;
auto uidProcessState = CreateUidProcessState();
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index d1f89775ed6a..bb2ede4ddc2b 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -73,9 +73,9 @@ TEST(DurationMetricTrackerTest, TestFirstBucket) {
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /*no condition*/, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions, 5,
- 600 * NS_PER_SEC + NS_PER_SEC / 2);
+ kConfigKey, metric, -1 /*no condition*/, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
EXPECT_EQ(600500000000, durationProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, durationProducer.mCurrentBucketNum);
@@ -101,9 +101,9 @@ TEST(DurationMetricTrackerTest, TestNoCondition) {
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /*no condition*/, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /*no condition*/, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
@@ -145,8 +145,9 @@ TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
DurationMetricProducer durationProducer(
kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
- 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ -1 /*what index not needed*/, 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
+ bucketStartTimeNs, bucketStartTimeNs);
durationProducer.mCondition = ConditionState::kFalse;
EXPECT_FALSE(durationProducer.mCondition);
@@ -195,8 +196,9 @@ TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
DurationMetricProducer durationProducer(
kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
- 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ -1 /*what index not needed*/, 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
+ bucketStartTimeNs, bucketStartTimeNs);
EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -240,9 +242,9 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDuration) {
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -303,9 +305,9 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationWithSplitInFollo
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -367,9 +369,9 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationAnomaly) {
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -413,9 +415,9 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDuration) {
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
int64_t startTimeNs = bucketStartTimeNs + 1;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -467,9 +469,9 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextB
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
int64_t startTimeNs = bucketStartTimeNs + 1;
LogEvent event1(/*uid=*/0, /*pid=*/0);
diff --git a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
index 9e2350b33018..9ab7e47dce43 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
@@ -875,12 +875,50 @@ TEST(MetricsManagerTest, TestCreateAnomalyTrackerDurationTooLong) {
FieldMatcher dimensions;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
vector<sp<MetricProducer>> metricProducers({new DurationMetricProducer(
- kConfigKey, metric, -1 /*no condition*/, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, 0x0123456789, dimensions, 0, 0)});
+ kConfigKey, metric, -1 /*no condition*/, {}, -1 /* what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, 0x0123456789, dimensions, 0, 0)});
sp<AlarmMonitor> anomalyAlarmMonitor;
EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt);
}
+TEST(MetricsManagerTest, TestCreateDurationProducerDimensionsInWhatInvalid) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT");
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+ Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ // The predicate is dimensioning by first attribution node by uid.
+ FieldMatcher dimensions =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ DurationMetric* durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ // The metric is dimensioning by first attribution node by uid AND tag.
+ // Invalid since the predicate only dimensions by uid.
+ *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidAndOtherDimensions(
+ util::WAKELOCK_STATE_CHANGED, {Position::FIRST}, {3 /* tag */});
+ durationMetric->set_bucket(FIVE_MINUTES);
+
+ ConfigKey key(123, 987);
+ uint64_t timeNs = 456;
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ sp<UidMap> uidMap;
+ sp<MetricsManager> metricsManager =
+ new MetricsManager(key, config, timeNs, timeNs, uidMap, pullerManager,
+ anomalyAlarmMonitor, periodicAlarmMonitor);
+ EXPECT_FALSE(metricsManager->isConfigValid());
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 1761d5d9e1fa..153b696808dc 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -1091,6 +1091,21 @@ void ValidateAttributionUidAndTagDimension(
.value_tuple().dimensions_value(1).value_str(), tag);
}
+void ValidateStateValue(const google::protobuf::RepeatedPtrField<StateValue>& stateValues,
+ int atomId, int64_t value) {
+ ASSERT_EQ(stateValues.size(), 1);
+ ASSERT_EQ(stateValues[0].atom_id(), atomId);
+ switch (stateValues[0].contents_case()) {
+ case StateValue::ContentsCase::kValue:
+ EXPECT_EQ(stateValues[0].value(), (int32_t)value);
+ break;
+ case StateValue::ContentsCase::kGroupId:
+ EXPECT_EQ(stateValues[0].group_id(), value);
+ break;
+ default:
+ FAIL() << "State value should have either a value or a group id";
+ }
+}
bool EqualsTo(const DimensionsValue& s1, const DimensionsValue& s2) {
if (s1.field() != s2.field()) {
return false;
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 1220019e2353..c51491244fd8 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -347,6 +347,8 @@ void ValidateAttributionUidAndTagDimension(
const DimensionsValue& value, int atomId, int uid, const std::string& tag);
void ValidateAttributionUidAndTagDimension(
const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag);
+void ValidateStateValue(const google::protobuf::RepeatedPtrField<StateValue>& stateValues,
+ int atomId, int64_t value);
struct DimensionsPair {
DimensionsPair(DimensionsValue m1, google::protobuf::RepeatedPtrField<StateValue> m2)
diff --git a/core/api/current.txt b/core/api/current.txt
index 9cec7a67d6ec..ed92c2977a2f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9098,6 +9098,15 @@ package android.bluetooth {
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR;
}
+ public final class BluetoothLeAudio implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void close();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) protected void finalize();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+ method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
+ field public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
+ }
+
public final class BluetoothManager {
method public android.bluetooth.BluetoothAdapter getAdapter();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
@@ -10319,7 +10328,7 @@ package android.content {
method public int checkPermission(String, int, int);
method public int checkSelfPermission(String);
method public int checkUriPermission(android.net.Uri, int, int, int);
- method public int checkUriPermission(android.net.Uri, String, String, int, int, int);
+ method public int checkUriPermission(@Nullable android.net.Uri, @Nullable String, @Nullable String, int, int, int);
method @Deprecated public void clearWallpaper() throws java.io.IOException;
method public android.content.Context createConfigurationContext(android.content.res.Configuration);
method public android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -10330,13 +10339,13 @@ package android.content {
method public boolean deleteDatabase(String);
method public boolean deleteFile(String);
method public boolean deleteSharedPreferences(String);
- method public void enforceCallingOrSelfPermission(String, String);
+ method public void enforceCallingOrSelfPermission(String, @Nullable String);
method public void enforceCallingOrSelfUriPermission(android.net.Uri, int, String);
- method public void enforceCallingPermission(String, String);
+ method public void enforceCallingPermission(String, @Nullable String);
method public void enforceCallingUriPermission(android.net.Uri, int, String);
- method public void enforcePermission(String, int, int, String);
+ method public void enforcePermission(String, int, int, @Nullable String);
method public void enforceUriPermission(android.net.Uri, int, int, int, String);
- method public void enforceUriPermission(android.net.Uri, String, String, int, int, int, String);
+ method public void enforceUriPermission(@Nullable android.net.Uri, @Nullable String, @Nullable String, int, int, int, @Nullable String);
method public String[] fileList();
method public android.content.Context getApplicationContext();
method public android.content.pm.ApplicationInfo getApplicationInfo();
@@ -10349,9 +10358,9 @@ package android.content {
method public java.io.File getDataDir();
method public java.io.File getDatabasePath(String);
method public java.io.File getDir(String, int);
- method public java.io.File getExternalCacheDir();
+ method @Nullable public java.io.File getExternalCacheDir();
method public java.io.File[] getExternalCacheDirs();
- method public java.io.File getExternalFilesDir(String);
+ method @Nullable public java.io.File getExternalFilesDir(@Nullable String);
method public java.io.File[] getExternalFilesDirs(String);
method public java.io.File[] getExternalMediaDirs();
method public java.io.File getFileStreamPath(String);
@@ -10379,40 +10388,40 @@ package android.content {
method public java.io.FileInputStream openFileInput(String) throws java.io.FileNotFoundException;
method public java.io.FileOutputStream openFileOutput(String, int) throws java.io.FileNotFoundException;
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
- method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
+ method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, @Nullable android.database.DatabaseErrorHandler);
method @Deprecated public android.graphics.drawable.Drawable peekWallpaper();
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler, int);
+ method public android.content.Intent registerReceiver(@Nullable android.content.BroadcastReceiver, android.content.IntentFilter);
+ method public android.content.Intent registerReceiver(@Nullable android.content.BroadcastReceiver, android.content.IntentFilter, int);
+ method public android.content.Intent registerReceiver(@Nullable android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler);
+ method public android.content.Intent registerReceiver(@Nullable android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
method @Deprecated public void removeStickyBroadcast(android.content.Intent);
method @Deprecated public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void revokeUriPermission(android.net.Uri, int);
method public void revokeUriPermission(String, android.net.Uri, int);
method public void sendBroadcast(android.content.Intent);
- method public void sendBroadcast(android.content.Intent, String);
+ method public void sendBroadcast(android.content.Intent, @Nullable String);
method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, String);
- method public void sendOrderedBroadcast(android.content.Intent, String);
- method public void sendOrderedBroadcast(android.content.Intent, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
+ method public void sendOrderedBroadcast(android.content.Intent, @Nullable String);
+ method public void sendOrderedBroadcast(android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method public void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, int, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, @Nullable String, @Nullable android.os.Bundle, @Nullable android.os.Bundle);
- method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
+ method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @Deprecated public void sendStickyBroadcast(android.content.Intent);
method @Deprecated public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
- method @Deprecated public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
- method @Deprecated public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
+ method @Deprecated public void sendStickyOrderedBroadcast(android.content.Intent, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+ method @Deprecated public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method public void setTheme(int);
method @Deprecated public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
method @Deprecated public void setWallpaper(java.io.InputStream) throws java.io.IOException;
method public void startActivities(android.content.Intent[]);
- method public void startActivities(android.content.Intent[], android.os.Bundle);
+ method public void startActivities(android.content.Intent[], @Nullable android.os.Bundle);
method public void startActivity(android.content.Intent);
- method public void startActivity(android.content.Intent, android.os.Bundle);
- method public android.content.ComponentName startForegroundService(android.content.Intent);
- method public boolean startInstrumentation(android.content.ComponentName, String, android.os.Bundle);
+ method public void startActivity(android.content.Intent, @Nullable android.os.Bundle);
+ method @Nullable public android.content.ComponentName startForegroundService(android.content.Intent);
+ method public boolean startInstrumentation(android.content.ComponentName, @Nullable String, @Nullable android.os.Bundle);
method public void startIntentSender(android.content.IntentSender, @Nullable android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
method public void startIntentSender(android.content.IntentSender, @Nullable android.content.Intent, int, int, int, @Nullable android.os.Bundle) throws android.content.IntentSender.SendIntentException;
- method public android.content.ComponentName startService(android.content.Intent);
+ method @Nullable public android.content.ComponentName startService(android.content.Intent);
method public boolean stopService(android.content.Intent);
method public void unbindService(android.content.ServiceConnection);
method public void unregisterReceiver(android.content.BroadcastReceiver);
@@ -45156,6 +45165,7 @@ package android.telephony {
field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
+ field public static final String KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING = "call_composer_picture_server_url_string";
field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array";
field public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string";
field public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool";
@@ -45345,6 +45355,7 @@ package android.telephony {
field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
+ field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool";
field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
field public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL = "support_add_conference_participants_bool";
field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool";
@@ -47662,6 +47673,7 @@ package android.telephony.ims.feature {
public static class MmTelFeature.MmTelCapabilities {
method public final boolean isCapable(int);
+ field public static final int CAPABILITY_TYPE_CALL_COMPOSER = 16; // 0x10
field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8
field public static final int CAPABILITY_TYPE_UT = 4; // 0x4
field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d9a9c265f3b8..8eb1b5f084fe 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1795,11 +1795,11 @@ package android.content {
public class ContextWrapper extends android.content.Context {
method public android.content.Context createCredentialProtectedStorageContext();
- method public java.io.File getPreloadsFileCache();
+ method @Nullable public java.io.File getPreloadsFileCache();
method public boolean isCredentialProtectedStorage();
- method public void sendBroadcast(android.content.Intent, String, android.os.Bundle);
- method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.os.Bundle);
- method public void sendOrderedBroadcast(android.content.Intent, String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
+ method public void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
+ method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
+ method public void sendOrderedBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
}
public class Intent implements java.lang.Cloneable android.os.Parcelable {
@@ -6506,6 +6506,7 @@ package android.net {
field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
field public static final int TYPE_NONE = -1; // 0xffffffff
+ field @Deprecated public static final int TYPE_PROXY = 16; // 0x10
field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
}
@@ -9707,6 +9708,33 @@ package android.telecom {
field @Deprecated public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
}
+ public final class BluetoothCallQualityReport implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=0) public int getNegativeAcknowledgementCount();
+ method @IntRange(from=0) public int getPacketsNotReceivedCount();
+ method @IntRange(from=0) public int getRetransmittedPacketsCount();
+ method @IntRange(from=0xffffff81, to=20) public int getRssiDbm();
+ method public long getSentTimestampMillis();
+ method public int getSnrDb();
+ method public boolean isChoppyVoice();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telecom.BluetoothCallQualityReport> CREATOR;
+ field public static final String EVENT_BLUETOOTH_CALL_QUALITY_REPORT = "android.telecom.event.BLUETOOTH_CALL_QUALITY_REPORT";
+ field public static final String EXTRA_BLUETOOTH_CALL_QUALITY_REPORT = "android.telecom.extra.BLUETOOTH_CALL_QUALITY_REPORT";
+ }
+
+ public static final class BluetoothCallQualityReport.Builder {
+ ctor public BluetoothCallQualityReport.Builder();
+ method @NonNull public android.telecom.BluetoothCallQualityReport build();
+ method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setChoppyVoice(boolean);
+ method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setNegativeAcknowledgementCount(int);
+ method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setPacketsNotReceivedCount(int);
+ method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setRetransmittedPacketsCount(int);
+ method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setRssiDbm(int);
+ method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setSentTimestampMillis(long);
+ method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setSnrDb(int);
+ }
+
public final class Call {
method @Deprecated public void addListener(android.telecom.Call.Listener);
method public void enterBackgroundAudioProcessing();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e392ed7b6e2d..51edd03515e1 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -18,6 +18,7 @@ package android {
field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
+ field public static final String MODIFY_REFRESH_RATE_SWITCHING_TYPE = "android.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE";
field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS";
@@ -743,9 +744,14 @@ package android.hardware.display {
}
public final class DisplayManager {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE) public int getRefreshRateSwitchingType();
method public boolean isMinimalPostProcessingRequested(int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE) public void setRefreshRateSwitchingType(int);
method @RequiresPermission(android.Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS) public void setShouldAlwaysRespectAppRequestedMode(boolean);
method @RequiresPermission(android.Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS) public boolean shouldAlwaysRespectAppRequestedMode();
+ field public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2; // 0x2
+ field public static final int SWITCHING_TYPE_NONE = 0; // 0x0
+ field public static final int SWITCHING_TYPE_WITHIN_GROUPS = 1; // 0x1
field public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 512; // 0x200
field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5f2d3a2b997b..433182b38efd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -85,6 +85,7 @@ import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.HardwareRenderer;
+import android.graphics.Typeface;
import android.hardware.display.DisplayManagerGlobal;
import android.inputmethodservice.InputMethodService;
import android.media.MediaFrameworkInitializer;
@@ -117,6 +118,7 @@ import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SharedMemory;
import android.os.StatsFrameworkInitializer;
import android.os.StatsServiceManager;
import android.os.StrictMode;
@@ -844,6 +846,8 @@ public final class ActivityThread extends ClientTransactionHandler {
long[] disabledCompatChanges;
+ SharedMemory mSerializedSystemFontMap;
+
@Override
public String toString() {
return "AppBindData{appInfo=" + appInfo + "}";
@@ -1054,7 +1058,8 @@ public final class ActivityThread extends ClientTransactionHandler {
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, AutofillOptions autofillOptions,
- ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
+ ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges,
+ SharedMemory serializedSystemFontMap) {
if (services != null) {
if (false) {
// Test code to make sure the app could see the passed-in services.
@@ -1103,6 +1108,7 @@ public final class ActivityThread extends ClientTransactionHandler {
data.autofillOptions = autofillOptions;
data.contentCaptureOptions = contentCaptureOptions;
data.disabledCompatChanges = disabledCompatChanges;
+ data.mSerializedSystemFontMap = serializedSystemFontMap;
sendMessage(H.BIND_APPLICATION, data);
}
@@ -6380,6 +6386,15 @@ public final class ActivityThread extends ClientTransactionHandler {
*/
LocaleList.setDefault(data.config.getLocales());
+ if (Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+ try {
+ Typeface.setSystemFontMap(data.mSerializedSystemFontMap);
+ } catch (IOException | ErrnoException e) {
+ Slog.e(TAG, "Failed to parse serialized system font map");
+ Typeface.loadPreinstalledSystemFontMap();
+ }
+ }
+
synchronized (mResourcesManager) {
/*
* Update the system configuration since its preloaded and might not
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 22ca42eb9cf4..890e957bdff4 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -43,6 +43,7 @@ import android.os.IInterface;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
+import android.os.SharedMemory;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
@@ -75,7 +76,8 @@ oneway interface IApplicationThread {
boolean restrictedBackupMode, boolean persistent, in Configuration config,
in CompatibilityInfo compatInfo, in Map services,
in Bundle coreSettings, in String buildSerial, in AutofillOptions autofillOptions,
- in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges);
+ in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges,
+ in SharedMemory serializedSystemFontMap);
void runIsolatedEntryPoint(in String entryPoint, in String[] entryPointArgs);
void scheduleExit();
void scheduleServiceArgs(IBinder token, in ParceledListSlice args);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d5977e7711fd..a1135809fd4c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5932,8 +5932,7 @@ public class Notification implements Parcelable
}
int color;
- int background = mContext.getColor(
- com.android.internal.R.color.notification_material_background_color);
+ int background = obtainBackgroundColor();
if (rawColor == COLOR_DEFAULT) {
ensureColors(p);
color = ContrastColorUtil.resolveDefaultColor(mContext, background, mInNightMode);
@@ -5966,8 +5965,7 @@ public class Notification implements Parcelable
if (mNeutralColor != COLOR_INVALID) {
return mNeutralColor;
}
- int background = mContext.getColor(
- com.android.internal.R.color.notification_material_background_color);
+ int background = obtainBackgroundColor();
mNeutralColor = ContrastColorUtil.resolveDefaultColor(mContext, background,
mInNightMode);
if (Color.alpha(mNeutralColor) < 255) {
@@ -6118,6 +6116,21 @@ public class Notification implements Parcelable
return mN;
}
+ private @ColorInt int obtainBackgroundColor() {
+ int defaultColor = mInNightMode ? Color.BLACK : Color.WHITE;
+ Resources.Theme theme = mContext.getTheme();
+ if (theme == null) {
+ return defaultColor;
+ }
+ TypedArray ta = theme.obtainStyledAttributes(new int[]{R.attr.colorBackground});
+ if (ta == null) {
+ return defaultColor;
+ }
+ int background = ta.getColor(0, defaultColor);
+ ta.recycle();
+ return background;
+ }
+
/**
* Apply this Builder to an existing {@link Notification} object.
*
@@ -6251,8 +6264,7 @@ public class Notification implements Parcelable
private int resolveBackgroundColor(StandardTemplateParams p) {
int backgroundColor = getBackgroundColor(p);
if (backgroundColor == COLOR_DEFAULT) {
- backgroundColor = mContext.getColor(
- com.android.internal.R.color.notification_material_background_color);
+ backgroundColor = obtainBackgroundColor();
}
return backgroundColor;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 7287acdd0241..392d6fbe53d6 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -194,6 +194,7 @@ import android.telephony.TelephonyRegistryManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import android.uwb.UwbManager;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.WindowManager;
@@ -732,6 +733,14 @@ public final class SystemServiceRegistry {
return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
}});
+ registerService(Context.UWB_SERVICE, UwbManager.class,
+ new CachedServiceFetcher<UwbManager>() {
+ @Override
+ public UwbManager createService(ContextImpl ctx) {
+ return UwbManager.getInstance();
+ }
+ });
+
registerService(Context.VIBRATOR_SERVICE, Vibrator.class,
new CachedServiceFetcher<Vibrator>() {
@Override
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
new file mode 100644
index 000000000000..3f00fa6f4181
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2020 HIMSA II K/S - www.himsa.com.
+ * Represented by EHIMA - www.ehima.com
+ *
+ * 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.bluetooth;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.CloseGuard;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the LeAudio profile.
+ *
+ * <p>BluetoothLeAudio is a proxy object for controlling the Bluetooth LE Audio
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothLeAudio proxy object.
+ *
+ * <p> Android only supports one set of connected Bluetooth LeAudio device at a time. Each
+ * method is protected with its appropriate permission.
+ */
+public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
+ private static final String TAG = "BluetoothLeAudio";
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ private CloseGuard mCloseGuard;
+
+ /**
+ * Intent used to broadcast the change in connection state of the LeAudio
+ * profile. Please note that in the binaural case, there will be two different LE devices for
+ * the left and right side and each device will have their own connection state changes.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent used to broadcast the selection of a connected device as active.
+ *
+ * <p>This intent will have one extra:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+ * be null if no device is active. </li>
+ * </ul>
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED =
+ "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED";
+
+ /**
+ * This represents an invalid group ID.
+ *
+ * @hide
+ */
+ public static final int GROUP_ID_INVALID = IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
+
+ private BluetoothAdapter mAdapter;
+ private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector =
+ new BluetoothProfileConnector(this, BluetoothProfile.LE_AUDIO, "BluetoothLeAudio",
+ IBluetoothLeAudio.class.getName()) {
+ @Override
+ public IBluetoothLeAudio getServiceInterface(IBinder service) {
+ return IBluetoothLeAudio.Stub.asInterface(Binder.allowBlocking(service));
+ }
+ };
+
+ /**
+ * Create a BluetoothLeAudio proxy object for interacting with the local
+ * Bluetooth LeAudio service.
+ */
+ /*package*/ BluetoothLeAudio(Context context, ServiceListener listener) {
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mProfileConnector.connect(context, listener);
+ mCloseGuard = new CloseGuard();
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void close() {
+ mProfileConnector.disconnect();
+ }
+
+ private IBluetoothLeAudio getService() {
+ return mProfileConnector.getService();
+ }
+
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ }
+
+ /**
+ * Initiate connection to a profile of the remote bluetooth device.
+ *
+ * <p> This API returns false in scenarios like the profile on the
+ * device is already connected or Bluetooth is not turned on.
+ * When this API returns true, it is guaranteed that
+ * connection state intent for the profile will be broadcasted with
+ * the state. Users can get the connection state of the profile
+ * from this intent.
+ *
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean connect(@Nullable BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled() && isValidDevice(device)) {
+ return service.connect(device);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Initiate disconnection from a profile
+ *
+ * <p> This API will return false in scenarios like the profile on the
+ * Bluetooth device is not in connected state etc. When this API returns,
+ * true, it is guaranteed that the connection state change
+ * intent will be broadcasted with the state. Users can get the
+ * disconnection state of the profile from this intent.
+ *
+ * <p> If the disconnection is initiated by a remote device, the state
+ * will transition from {@link #STATE_CONNECTED} to
+ * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
+ * host (local) device the state will transition from
+ * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
+ * state {@link #STATE_DISCONNECTED}. The transition to
+ * {@link #STATE_DISCONNECTING} can be used to distinguish between the
+ * two scenarios.
+ *
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean disconnect(@Nullable BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled() && isValidDevice(device)) {
+ return service.disconnect(device);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NonNull List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()) {
+ return service.getConnectedDevices();
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
+ @NonNull int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()) {
+ return service.getDevicesMatchingConnectionStates(states);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()
+ && isValidDevice(device)) {
+ return service.getConnectionState(device);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+
+ /**
+ * Select a connected device as active.
+ *
+ * The active device selection is per profile. An active device's
+ * purpose is profile-specific. For example, LeAudio audio
+ * streaming is to the active LeAudio device. If a remote device
+ * is not connected, it cannot be selected as active.
+ *
+ * <p> This API returns false in scenarios like the profile on the
+ * device is not connected or Bluetooth is not turned on.
+ * When this API returns true, it is guaranteed that the
+ * {@link #ACTION_LEAUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
+ * with the active device.
+ *
+ *
+ * @param device the remote Bluetooth device. Could be null to clear
+ * the active device and stop streaming audio to a Bluetooth device.
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setActiveDevice(@Nullable BluetoothDevice device) {
+ if (DBG) log("setActiveDevice(" + device + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()
+ && ((device == null) || isValidDevice(device))) {
+ service.setActiveDevice(device);
+ return true;
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Get the connected LeAudio devices that are active
+ *
+ * @return the list of active devices. Returns empty list on error.
+ * @hide
+ */
+ @NonNull
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public List<BluetoothDevice> getActiveDevices() {
+ if (VDBG) log("getActiveDevices()");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()) {
+ return service.getActiveDevices();
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<>();
+ }
+ }
+
+ /**
+ * Get device group id. Devices with same group id belong to same group (i.e left and right
+ * earbud)
+ * @param device LE Audio capable device
+ * @return group id that this device currently belongs to
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getGroupId(@NonNull BluetoothDevice device) {
+ if (VDBG) log("getGroupId()");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()) {
+ return service.getGroupId(device);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return GROUP_ID_INVALID;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return GROUP_ID_INVALID;
+ }
+ }
+
+ /**
+ * Set connection policy of the profile
+ *
+ * <p> The device should already be paired.
+ * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+ * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Paired bluetooth device
+ * @param connectionPolicy is the connection policy to set to for this profile
+ * @return true if connectionPolicy is set, false on error
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
+ if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()
+ && isValidDevice(device)) {
+ if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+ && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ return false;
+ }
+ return service.setConnectionPolicy(device, connectionPolicy);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Get the connection policy of the profile.
+ *
+ * <p> The connection policy can be any of:
+ * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+ * {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Bluetooth device
+ * @return connection policy of the device
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
+ if (VDBG) log("getConnectionPolicy(" + device + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()
+ && isValidDevice(device)) {
+ return service.getConnectionPolicy(device);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ }
+ }
+
+
+ /**
+ * Helper for converting a state to a string.
+ *
+ * For debug use only - strings are not internationalized.
+ *
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_DISCONNECTED:
+ return "disconnected";
+ case STATE_CONNECTING:
+ return "connecting";
+ case STATE_CONNECTED:
+ return "connected";
+ case STATE_DISCONNECTING:
+ return "disconnecting";
+ default:
+ return "<unknown state " + state + ">";
+ }
+ }
+
+ private boolean isValidDevice(@Nullable BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index db851c4f33b9..c31b04e81456 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -207,12 +207,19 @@ public interface BluetoothProfile {
int HEARING_AID = 21;
/**
+ * LE Audio Device
+ *
+ * @hide
+ */
+ int LE_AUDIO = 22;
+
+ /**
* Max profile ID. This value should be updated whenever a new profile is added to match
* the largest value assigned to a profile.
*
* @hide
*/
- int MAX_PROFILE_ID = 21;
+ int MAX_PROFILE_ID = 22;
/**
* Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8f92bf1e3253..d920fb3e97e6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3544,6 +3544,7 @@ public abstract class Context {
LIGHTS_SERVICE,
//@hide: PEOPLE_SERVICE,
//@hide: DEVICE_STATE_SERVICE,
+ UWB_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -5260,6 +5261,15 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.uwb.UwbManager}.
+ *
+ * @see #getSystemService(String)
+ * @hide
+ */
+ public static final String UWB_SERVICE = "uwb";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.app.DreamManager} for controlling Dream states.
*
* @see #getSystemService(String)
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index b0c47bdfd864..56da3cb0eb02 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -270,7 +270,7 @@ public class ContextWrapper extends Context {
}
@Override
- public File getExternalFilesDir(String type) {
+ public @Nullable File getExternalFilesDir(@Nullable String type) {
return mBase.getExternalFilesDir(type);
}
@@ -300,7 +300,7 @@ public class ContextWrapper extends Context {
}
@Override
- public File getExternalCacheDir() {
+ public @Nullable File getExternalCacheDir() {
return mBase.getExternalCacheDir();
}
@@ -322,7 +322,7 @@ public class ContextWrapper extends Context {
/** @hide **/
@Override
- public File getPreloadsFileCache() {
+ public @Nullable File getPreloadsFileCache() {
return mBase.getPreloadsFileCache();
}
@@ -333,7 +333,7 @@ public class ContextWrapper extends Context {
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
- DatabaseErrorHandler errorHandler) {
+ @Nullable DatabaseErrorHandler errorHandler) {
return mBase.openOrCreateDatabase(name, mode, factory, errorHandler);
}
@@ -412,7 +412,7 @@ public class ContextWrapper extends Context {
/** @hide **/
public void startActivityForResult(
- String who, Intent intent, int requestCode, Bundle options) {
+ String who, Intent intent, int requestCode, @Nullable Bundle options) {
mBase.startActivityForResult(who, intent, requestCode, options);
}
@@ -422,13 +422,13 @@ public class ContextWrapper extends Context {
}
@Override
- public void startActivity(Intent intent, Bundle options) {
+ public void startActivity(Intent intent, @Nullable Bundle options) {
mBase.startActivity(intent, options);
}
/** @hide */
@Override
- public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
+ public void startActivityAsUser(Intent intent, @Nullable Bundle options, UserHandle user) {
mBase.startActivityAsUser(intent, options, user);
}
@@ -438,13 +438,14 @@ public class ContextWrapper extends Context {
}
@Override
- public void startActivities(Intent[] intents, Bundle options) {
+ public void startActivities(Intent[] intents, @Nullable Bundle options) {
mBase.startActivities(intents, options);
}
/** @hide */
@Override
- public int startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) {
+ public int startActivitiesAsUser(Intent[] intents, @Nullable Bundle options,
+ UserHandle userHandle) {
return mBase.startActivitiesAsUser(intents, options, userHandle);
}
@@ -472,7 +473,7 @@ public class ContextWrapper extends Context {
}
@Override
- public void sendBroadcast(Intent intent, String receiverPermission) {
+ public void sendBroadcast(Intent intent, @Nullable String receiverPermission) {
mBase.sendBroadcast(intent, receiverPermission);
}
@@ -493,27 +494,28 @@ public class ContextWrapper extends Context {
/** @hide */
@SystemApi
@Override
- public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
+ public void sendBroadcast(Intent intent, @Nullable String receiverPermission,
+ @Nullable Bundle options) {
mBase.sendBroadcast(intent, receiverPermission, options);
}
/** @hide */
@Override
- public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
+ public void sendBroadcast(Intent intent, @Nullable String receiverPermission, int appOp) {
mBase.sendBroadcast(intent, receiverPermission, appOp);
}
@Override
public void sendOrderedBroadcast(Intent intent,
- String receiverPermission) {
+ @Nullable String receiverPermission) {
mBase.sendOrderedBroadcast(intent, receiverPermission);
}
@Override
public void sendOrderedBroadcast(
- Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
- Handler scheduler, int initialCode, String initialData,
- Bundle initialExtras) {
+ Intent intent, @Nullable String receiverPermission,
+ @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+ int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
mBase.sendOrderedBroadcast(intent, receiverPermission,
resultReceiver, scheduler, initialCode,
initialData, initialExtras);
@@ -523,10 +525,9 @@ public class ContextWrapper extends Context {
@SystemApi
@Override
public void sendOrderedBroadcast(
- Intent intent, String receiverPermission, Bundle options,
- BroadcastReceiver resultReceiver,
- Handler scheduler, int initialCode, String initialData,
- Bundle initialExtras) {
+ Intent intent, @Nullable String receiverPermission, @Nullable Bundle options,
+ @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+ int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
mBase.sendOrderedBroadcast(intent, receiverPermission,
options, resultReceiver, scheduler, initialCode,
initialData, initialExtras);
@@ -535,9 +536,9 @@ public class ContextWrapper extends Context {
/** @hide */
@Override
public void sendOrderedBroadcast(
- Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
- Handler scheduler, int initialCode, String initialData,
- Bundle initialExtras) {
+ Intent intent, @Nullable String receiverPermission, int appOp,
+ @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+ int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
mBase.sendOrderedBroadcast(intent, receiverPermission, appOp,
resultReceiver, scheduler, initialCode,
initialData, initialExtras);
@@ -557,21 +558,22 @@ public class ContextWrapper extends Context {
/** @hide */
@Override
public void sendBroadcastAsUser(Intent intent, UserHandle user,
- String receiverPermission, Bundle options) {
+ @Nullable String receiverPermission, @Nullable Bundle options) {
mBase.sendBroadcastAsUser(intent, user, receiverPermission, options);
}
/** @hide */
@Override
public void sendBroadcastAsUser(Intent intent, UserHandle user,
- String receiverPermission, int appOp) {
+ @Nullable String receiverPermission, int appOp) {
mBase.sendBroadcastAsUser(intent, user, receiverPermission, appOp);
}
@Override
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
- String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
- int initialCode, String initialData, Bundle initialExtras) {
+ @Nullable String receiverPermission, @Nullable BroadcastReceiver resultReceiver,
+ @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+ @Nullable Bundle initialExtras) {
mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, resultReceiver,
scheduler, initialCode, initialData, initialExtras);
}
@@ -579,8 +581,9 @@ public class ContextWrapper extends Context {
/** @hide */
@Override
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
- String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
- Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+ @Nullable String receiverPermission, int appOp,
+ @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+ int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, resultReceiver,
scheduler, initialCode, initialData, initialExtras);
}
@@ -588,8 +591,9 @@ public class ContextWrapper extends Context {
/** @hide */
@Override
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
- String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
- Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+ @Nullable String receiverPermission, int appOp, @Nullable Bundle options,
+ @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+ int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, options,
resultReceiver, scheduler, initialCode, initialData, initialExtras);
}
@@ -621,10 +625,9 @@ public class ContextWrapper extends Context {
@Override
@Deprecated
- public void sendStickyOrderedBroadcast(
- Intent intent, BroadcastReceiver resultReceiver,
- Handler scheduler, int initialCode, String initialData,
- Bundle initialExtras) {
+ public void sendStickyOrderedBroadcast(Intent intent,
+ @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+ int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
mBase.sendStickyOrderedBroadcast(intent,
resultReceiver, scheduler, initialCode,
initialData, initialExtras);
@@ -645,16 +648,17 @@ public class ContextWrapper extends Context {
/** @hide */
@Override
@Deprecated
- public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
+ public void sendStickyBroadcastAsUser(Intent intent, UserHandle user,
+ @Nullable Bundle options) {
mBase.sendStickyBroadcastAsUser(intent, user, options);
}
@Override
@Deprecated
public void sendStickyOrderedBroadcastAsUser(Intent intent,
- UserHandle user, BroadcastReceiver resultReceiver,
- Handler scheduler, int initialCode, String initialData,
- Bundle initialExtras) {
+ UserHandle user, @Nullable BroadcastReceiver resultReceiver,
+ @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+ @Nullable Bundle initialExtras) {
mBase.sendStickyOrderedBroadcastAsUser(intent, user, resultReceiver,
scheduler, initialCode, initialData, initialExtras);
}
@@ -666,29 +670,26 @@ public class ContextWrapper extends Context {
}
@Override
- public Intent registerReceiver(
- BroadcastReceiver receiver, IntentFilter filter) {
+ public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
@Override
- public Intent registerReceiver(
- BroadcastReceiver receiver, IntentFilter filter, int flags) {
+ public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter,
+ int flags) {
return mBase.registerReceiver(receiver, filter, flags);
}
@Override
- public Intent registerReceiver(
- BroadcastReceiver receiver, IntentFilter filter,
- String broadcastPermission, Handler scheduler) {
+ public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter,
+ @Nullable String broadcastPermission, @Nullable Handler scheduler) {
return mBase.registerReceiver(receiver, filter, broadcastPermission,
scheduler);
}
@Override
- public Intent registerReceiver(
- BroadcastReceiver receiver, IntentFilter filter,
- String broadcastPermission, Handler scheduler, int flags) {
+ public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter,
+ @Nullable String broadcastPermission, @Nullable Handler scheduler, int flags) {
return mBase.registerReceiver(receiver, filter, broadcastPermission,
scheduler, flags);
}
@@ -706,9 +707,9 @@ public class ContextWrapper extends Context {
/** @hide */
@Override
@UnsupportedAppUsage
- public Intent registerReceiverAsUser(
- BroadcastReceiver receiver, UserHandle user, IntentFilter filter,
- String broadcastPermission, Handler scheduler) {
+ public Intent registerReceiverAsUser(@Nullable BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, @Nullable String broadcastPermission,
+ @Nullable Handler scheduler) {
return mBase.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
scheduler);
}
@@ -719,12 +720,12 @@ public class ContextWrapper extends Context {
}
@Override
- public ComponentName startService(Intent service) {
+ public @Nullable ComponentName startService(Intent service) {
return mBase.startService(service);
}
@Override
- public ComponentName startForegroundService(Intent service) {
+ public @Nullable ComponentName startForegroundService(Intent service) {
return mBase.startForegroundService(service);
}
@@ -736,14 +737,14 @@ public class ContextWrapper extends Context {
/** @hide */
@Override
@UnsupportedAppUsage
- public ComponentName startServiceAsUser(Intent service, UserHandle user) {
+ public @Nullable ComponentName startServiceAsUser(Intent service, UserHandle user) {
return mBase.startServiceAsUser(service, user);
}
/** @hide */
@Override
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) {
+ public @Nullable ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) {
return mBase.startForegroundServiceAsUser(service, user);
}
@@ -797,12 +798,12 @@ public class ContextWrapper extends Context {
@Override
public boolean startInstrumentation(ComponentName className,
- String profileFile, Bundle arguments) {
+ @Nullable String profileFile, @Nullable Bundle arguments) {
return mBase.startInstrumentation(className, profileFile, arguments);
}
@Override
- public Object getSystemService(String name) {
+ public @Nullable Object getSystemService(String name) {
return mBase.getSystemService(name);
}
@@ -839,18 +840,18 @@ public class ContextWrapper extends Context {
@Override
public void enforcePermission(
- String permission, int pid, int uid, String message) {
+ String permission, int pid, int uid, @Nullable String message) {
mBase.enforcePermission(permission, pid, uid, message);
}
@Override
- public void enforceCallingPermission(String permission, String message) {
+ public void enforceCallingPermission(String permission, @Nullable String message) {
mBase.enforceCallingPermission(permission, message);
}
@Override
public void enforceCallingOrSelfPermission(
- String permission, String message) {
+ String permission, @Nullable String message) {
mBase.enforceCallingOrSelfPermission(permission, message);
}
@@ -891,8 +892,8 @@ public class ContextWrapper extends Context {
}
@Override
- public int checkUriPermission(Uri uri, String readPermission,
- String writePermission, int pid, int uid, int modeFlags) {
+ public int checkUriPermission(@Nullable Uri uri, @Nullable String readPermission,
+ @Nullable String writePermission, int pid, int uid, int modeFlags) {
return mBase.checkUriPermission(uri, readPermission, writePermission,
pid, uid, modeFlags);
}
@@ -917,8 +918,8 @@ public class ContextWrapper extends Context {
@Override
public void enforceUriPermission(
- Uri uri, String readPermission, String writePermission,
- int pid, int uid, int modeFlags, String message) {
+ @Nullable Uri uri, @Nullable String readPermission, @Nullable String writePermission,
+ int pid, int uid, int modeFlags, @Nullable String message) {
mBase.enforceUriPermission(
uri, readPermission, writePermission, pid, uid, modeFlags,
message);
@@ -1063,7 +1064,7 @@ public class ContextWrapper extends Context {
* @hide
*/
@Override
- public IBinder getActivityToken() {
+ public @Nullable IBinder getActivityToken() {
return mBase.getActivityToken();
}
@@ -1071,7 +1072,7 @@ public class ContextWrapper extends Context {
* @hide
*/
@Override
- public IBinder getWindowContextToken() {
+ public @Nullable IBinder getWindowContextToken() {
return mBase != null ? mBase.getWindowContextToken() : null;
}
@@ -1079,8 +1080,8 @@ public class ContextWrapper extends Context {
* @hide
*/
@Override
- public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
- int flags) {
+ public @Nullable IServiceConnection getServiceDispatcher(ServiceConnection conn,
+ Handler handler, int flags) {
return mBase.getServiceDispatcher(conn, handler, flags);
}
@@ -1142,7 +1143,7 @@ public class ContextWrapper extends Context {
* @hide
*/
@Override
- public ContentCaptureOptions getContentCaptureOptions() {
+ public @Nullable ContentCaptureOptions getContentCaptureOptions() {
return mBase == null ? null : mBase.getContentCaptureOptions();
}
@@ -1151,7 +1152,7 @@ public class ContextWrapper extends Context {
*/
@TestApi
@Override
- public void setContentCaptureOptions(ContentCaptureOptions options) {
+ public void setContentCaptureOptions(@Nullable ContentCaptureOptions options) {
if (mBase != null) {
mBase.setContentCaptureOptions(options);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 044b3b2e8284..19e4d148aee8 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -98,6 +98,11 @@ import java.util.Set;
* packages that are currently installed on the device.
*
* You can find this class through {@link Context#getPackageManager}.
+ *
+ * <p class="note"><strong>Note: </strong>If your app targets Android 11 (API level 30) or
+ * higher, the methods in this class each return a filtered list of apps. Learn more about how to
+ * <a href="/training/basics/intents/package-visibility">manage package visibility</a>.
+ * </p>
*/
public abstract class PackageManager {
private static final String TAG = "PackageManager";
@@ -2810,6 +2815,15 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device is capable of communicating with
+ * other devices via ultra wideband.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_UWB = "android.hardware.uwb";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports connecting to USB devices
* as the USB host.
*/
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index ca5eeb1863c7..9bae1ff4b906 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -19,6 +19,7 @@ package android.hardware.display;
import static android.view.Display.DEFAULT_DISPLAY;
import android.Manifest;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -38,9 +39,12 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.Surface;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+
/**
* Manages the properties of attached displays.
*/
@@ -336,6 +340,40 @@ public final class DisplayManager {
*/
public static final int VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP = 1 << 11;
+
+ /** @hide */
+ @IntDef(prefix = {"SWITCHING_TYPE_"}, value = {
+ SWITCHING_TYPE_NONE,
+ SWITCHING_TYPE_WITHIN_GROUPS,
+ SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SwitchingType {}
+
+ /**
+ * No mode switching will happen.
+ * @hide
+ */
+ @TestApi
+ public static final int SWITCHING_TYPE_NONE = 0;
+
+ /**
+ * Allow only refresh rate switching between modes in the same configuration group. This way
+ * only switches without visual interruptions for the user will be allowed.
+ * @hide
+ */
+ @TestApi
+ public static final int SWITCHING_TYPE_WITHIN_GROUPS = 1;
+
+ /**
+ * Allow refresh rate switching between all refresh rates even if the switch with have visual
+ * interruptions for the user.
+ * @hide
+ */
+ @TestApi
+ public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2;
+
+
/** @hide */
public DisplayManager(Context context) {
mContext = context;
@@ -875,6 +913,29 @@ public final class DisplayManager {
}
/**
+ * Sets the refresh rate switching type.
+ * This matches {@link android.provider.Settings.Secure.MATCH_CONTENT_FRAME_RATE}
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE)
+ public void setRefreshRateSwitchingType(@SwitchingType int newValue) {
+ mGlobal.setRefreshRateSwitchingType(newValue);
+ }
+
+ /**
+ * Returns the refresh rate switching type.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE)
+ @SwitchingType public int getRefreshRateSwitchingType() {
+ return mGlobal.getRefreshRateSwitchingType();
+ }
+
+ /**
* Listens for changes in available display devices.
*/
public interface DisplayListener {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 7b4889f0a1b3..77ae9471dfb0 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -725,6 +725,33 @@ public final class DisplayManagerGlobal {
}
}
+ /**
+ * Sets the refresh rate switching type.
+ *
+ * @hide
+ */
+ public void setRefreshRateSwitchingType(@DisplayManager.SwitchingType int newValue) {
+ try {
+ mDm.setRefreshRateSwitchingType(newValue);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the refresh rate switching type.
+ *
+ * @hide
+ */
+ @DisplayManager.SwitchingType
+ public int getRefreshRateSwitchingType() {
+ try {
+ return mDm.getRefreshRateSwitchingType();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
@Override
public void onDisplayEvent(int displayId, int event) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 85da6424377a..a9f78fa03a6d 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -134,4 +134,10 @@ interface IDisplayManager {
// battery etc.
void setShouldAlwaysRespectAppRequestedMode(boolean enabled);
boolean shouldAlwaysRespectAppRequestedMode();
+
+ // Sets the refresh rate switching type.
+ void setRefreshRateSwitchingType(int newValue);
+
+ // Returns the refresh rate switching type.
+ int getRefreshRateSwitchingType();
}
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 7cf0b10031ac..3cd13a212a4b 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -199,10 +199,11 @@ public abstract class AbstractInputMethodService extends Service
* Dumps the internal state of IME to a protocol buffer output stream.
*
* @param proto ProtoOutputStream to dump data to.
+ * @param icProto {@link InputConnection} call data in proto format.
* @hide
*/
@SuppressWarnings("HiddenAbstractMethod")
- public abstract void dumpProtoInternal(ProtoOutputStream proto);
+ public abstract void dumpProtoInternal(ProtoOutputStream proto, ProtoOutputStream icProto);
/**
* Implement this to handle {@link android.os.Binder#dump Binder.dump()}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 67e75d205f97..5576857d1f6b 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -25,6 +25,7 @@ import static android.inputmethodservice.InputMethodServiceProto.EXTRACTED_TOKEN
import static android.inputmethodservice.InputMethodServiceProto.EXTRACT_VIEW_HIDDEN;
import static android.inputmethodservice.InputMethodServiceProto.FULLSCREEN_APPLIED;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_BINDING;
+import static android.inputmethodservice.InputMethodServiceProto.INPUT_CONNECTION_CALL;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_EDITOR_INFO;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_STARTED;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_VIEW_STARTED;
@@ -742,7 +743,8 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
ImeTracing.getInstance().triggerServiceDump(
- "InputMethodService.InputMethodImpl#hideSoftInput", InputMethodService.this);
+ "InputMethodService.InputMethodImpl#hideSoftInput", InputMethodService.this,
+ null /* icProto */);
final boolean wasVisible = isInputViewShown();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
@@ -798,7 +800,8 @@ public class InputMethodService extends AbstractInputMethodService {
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
ImeTracing.getInstance().triggerServiceDump(
- "InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this);
+ "InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this,
+ null /* icProto */);
final boolean wasVisible = isInputViewShown();
if (dispatchOnShowInputRequested(flags, false)) {
@@ -2182,7 +2185,8 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this,
+ null /* icProto */);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
mDecorViewWasVisible = mDecorViewVisible;
mInShowWindow = true;
@@ -2260,7 +2264,8 @@ public class InputMethodService extends AbstractInputMethodService {
*/
private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) {
ImeTracing.getInstance().triggerServiceDump(
- "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", this);
+ "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", this,
+ null /* icProto */);
mPrivOps.applyImeVisibility(setVisible
? mCurShowInputToken : mCurHideInputToken, setVisible);
}
@@ -2285,7 +2290,8 @@ public class InputMethodService extends AbstractInputMethodService {
public void hideWindow() {
if (DEBUG) Log.v(TAG, "CALL: hideWindow");
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", this,
+ null /* icProto */);
mWindowVisible = false;
finishViews(false /* finishingInput */);
if (mDecorViewVisible) {
@@ -2356,7 +2362,8 @@ public class InputMethodService extends AbstractInputMethodService {
void doFinishInput() {
if (DEBUG) Log.v(TAG, "CALL: doFinishInput");
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", this,
+ null /* icProto */);
finishViews(true /* finishingInput */);
if (mInputStarted) {
mInlineSuggestionSessionController.notifyOnFinishInput();
@@ -2372,7 +2379,8 @@ public class InputMethodService extends AbstractInputMethodService {
if (!restarting && mInputStarted) {
doFinishInput();
}
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this,
+ null /* icProto */);
mInputStarted = true;
mStartedInputConnection = ic;
mInputEditorInfo = attribute;
@@ -2531,7 +2539,8 @@ public class InputMethodService extends AbstractInputMethodService {
* @param flags Provides additional operating flags.
*/
public void requestHideSelf(int flags) {
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", this,
+ null /* icProto */);
mPrivOps.hideMySoftInput(flags);
}
@@ -2544,7 +2553,8 @@ public class InputMethodService extends AbstractInputMethodService {
* @param flags Provides additional operating flags.
*/
public final void requestShowSelf(int flags) {
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", this,
+ null /* icProto */);
mPrivOps.showMySoftInput(flags);
}
@@ -3364,7 +3374,7 @@ public class InputMethodService extends AbstractInputMethodService {
* @hide
*/
@Override
- public final void dumpProtoInternal(ProtoOutputStream proto) {
+ public final void dumpProtoInternal(ProtoOutputStream proto, ProtoOutputStream icProto) {
final long token = proto.start(InputMethodServiceTraceProto.INPUT_METHOD_SERVICE);
mWindow.dumpDebug(proto, SOFT_INPUT_WINDOW);
proto.write(VIEWS_CREATED, mViewsCreated);
@@ -3393,6 +3403,9 @@ public class InputMethodService extends AbstractInputMethodService {
proto.write(STATUS_ICON, mStatusIcon);
mTmpInsets.dumpDebug(proto, LAST_COMPUTED_INSETS);
proto.write(SETTINGS_OBSERVER, Objects.toString(mSettingsObserver));
+ if (icProto != null) {
+ proto.write(INPUT_CONNECTION_CALL, icProto.getBytes());
+ }
proto.end(token);
}
}
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index c2586fa0c825..269bbf20c8b1 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -15,7 +15,6 @@
*/
package android.net;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
@@ -24,8 +23,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
/**
* A class allowing apps handling the {@link ConnectivityManager#ACTION_CAPTIVE_PORTAL_SIGN_IN}
* activity to indicate to the system different outcomes of captive portal sign in. This class is
@@ -75,17 +72,6 @@ public class CaptivePortal implements Parcelable {
private final IBinder mBinder;
/** @hide */
- @IntDef(value = {
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY,
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED,
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_UNWANTED,
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_WANTED_AS_IS,
- MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR,
- })
- public @interface EventId {
- }
-
- /** @hide */
public CaptivePortal(@NonNull IBinder binder) {
mBinder = binder;
}
@@ -176,7 +162,7 @@ public class CaptivePortal implements Parcelable {
* @hide
*/
@SystemApi
- public void logEvent(@EventId int eventId, @NonNull String packageName) {
+ public void logEvent(int eventId, @NonNull String packageName) {
try {
ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName);
} catch (RemoteException e) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4b38d6377f37..3f2c966f9ed2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -684,7 +684,7 @@ public class ConnectivityManager {
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage
+ @SystemApi
public static final int TYPE_PROXY = 16;
/**
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index d130bc5d37e7..b951aca6d680 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -67,7 +67,7 @@ public final class PowerManager {
/* NOTE: Wake lock levels were previously defined as a bit field, except that only a few
* combinations were actually supported so the bit field was removed. This explains
* why the numbering scheme is so odd. If adding a new wake lock level, any unused
- * value (in frameworks/base/core/proto/android/os/enums.proto) can be used.
+ * value (in frameworks/proto_logging/stats/enums/os/enums.proto) can be used.
*/
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 249a781509ac..b86b9ff814ae 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9797,12 +9797,13 @@ public final class Settings {
"use_blast_adapter_sv";
/**
- * If {@code true}, vendor provided window manager display settings will be ignored.
- * (0 = false, 1 = true)
+ * Path to the WindowManager display settings file. If unset, the default file path will
+ * be used.
+ *
* @hide
*/
- public static final String DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS =
- "ignore_vendor_display_settings";
+ public static final String DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH =
+ "wm_display_settings_path";
/**
* Whether user has enabled development settings.
diff --git a/core/java/android/util/imetracing/ImeTracing.java b/core/java/android/util/imetracing/ImeTracing.java
index 4058eef3e2a3..723f1dd15e23 100644
--- a/core/java/android/util/imetracing/ImeTracing.java
+++ b/core/java/android/util/imetracing/ImeTracing.java
@@ -110,15 +110,20 @@ public abstract class ImeTracing {
*
* @param where Place where the trace was triggered.
* @param immInstance The {@link InputMethodManager} instance to dump.
+ * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format.
*/
- public abstract void triggerClientDump(String where, InputMethodManager immInstance);
+ public abstract void triggerClientDump(String where, InputMethodManager immInstance,
+ ProtoOutputStream icProto);
/**
* Starts a proto dump of the currently connected InputMethodService information.
*
* @param where Place where the trace was triggered.
+ * @param service The {@link android.inputmethodservice.InputMethodService} to be dumped.
+ * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format.
*/
- public abstract void triggerServiceDump(String where, AbstractInputMethodService service);
+ public abstract void triggerServiceDump(String where, AbstractInputMethodService service,
+ ProtoOutputStream icProto);
/**
* Starts a proto dump of the InputMethodManagerService information.
diff --git a/core/java/android/util/imetracing/ImeTracingClientImpl.java b/core/java/android/util/imetracing/ImeTracingClientImpl.java
index 904b44da97d7..6cc652d942cc 100644
--- a/core/java/android/util/imetracing/ImeTracingClientImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingClientImpl.java
@@ -45,7 +45,8 @@ class ImeTracingClientImpl extends ImeTracing {
}
@Override
- public void triggerClientDump(String where, @NonNull InputMethodManager immInstance) {
+ public void triggerClientDump(String where, @NonNull InputMethodManager immInstance,
+ ProtoOutputStream icProto) {
if (!isEnabled() || !isAvailable()) {
return;
}
@@ -59,7 +60,7 @@ class ImeTracingClientImpl extends ImeTracing {
try {
ProtoOutputStream proto = new ProtoOutputStream();
- immInstance.dumpDebug(proto);
+ immInstance.dumpDebug(proto, icProto);
sendToService(proto.getBytes(), IME_TRACING_FROM_CLIENT, where);
} catch (RemoteException e) {
Log.e(TAG, "Exception while sending ime-related client dump to server", e);
@@ -69,7 +70,8 @@ class ImeTracingClientImpl extends ImeTracing {
}
@Override
- public void triggerServiceDump(String where, @NonNull AbstractInputMethodService service) {
+ public void triggerServiceDump(String where, @NonNull AbstractInputMethodService service,
+ ProtoOutputStream icProto) {
if (!isEnabled() || !isAvailable()) {
return;
}
@@ -83,7 +85,7 @@ class ImeTracingClientImpl extends ImeTracing {
try {
ProtoOutputStream proto = new ProtoOutputStream();
- service.dumpProtoInternal(proto);
+ service.dumpProtoInternal(proto, icProto);
sendToService(proto.getBytes(), IME_TRACING_FROM_IMS, where);
} catch (RemoteException e) {
Log.e(TAG, "Exception while sending ime-related service dump to server", e);
diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/android/util/imetracing/ImeTracingServerImpl.java
index d758d77fb2f2..e793c280afbc 100644
--- a/core/java/android/util/imetracing/ImeTracingServerImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingServerImpl.java
@@ -133,12 +133,14 @@ class ImeTracingServerImpl extends ImeTracing {
}
@Override
- public void triggerClientDump(String where, InputMethodManager immInstance) {
+ public void triggerClientDump(String where, InputMethodManager immInstance,
+ ProtoOutputStream icProto) {
// Intentionally left empty, this is implemented in ImeTracingClientImpl
}
@Override
- public void triggerServiceDump(String where, AbstractInputMethodService service) {
+ public void triggerServiceDump(String where, AbstractInputMethodService service,
+ ProtoOutputStream icProto) {
// Intentionally left empty, this is implemented in ImeTracingClientImpl
}
diff --git a/core/java/android/util/imetracing/InputConnectionHelper.java b/core/java/android/util/imetracing/InputConnectionHelper.java
new file mode 100644
index 000000000000..39f1e01eb4a9
--- /dev/null
+++ b/core/java/android/util/imetracing/InputConnectionHelper.java
@@ -0,0 +1,231 @@
+/*
+ * 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.util.imetracing;
+
+import static android.view.inputmethod.InputConnectionCallProto.GET_CURSOR_CAPS_MODE;
+import static android.view.inputmethod.InputConnectionCallProto.GET_EXTRACTED_TEXT;
+import static android.view.inputmethod.InputConnectionCallProto.GET_SELECTED_TEXT;
+import static android.view.inputmethod.InputConnectionCallProto.GET_SURROUNDING_TEXT;
+import static android.view.inputmethod.InputConnectionCallProto.GET_TEXT_AFTER_CURSOR;
+import static android.view.inputmethod.InputConnectionCallProto.GET_TEXT_BEFORE_CURSOR;
+import static android.view.inputmethod.InputConnectionCallProto.GetExtractedText.REQUEST;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.proto.ProtoOutputStream;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnectionCallProto.GetCursorCapsMode;
+import android.view.inputmethod.InputConnectionCallProto.GetExtractedText;
+import android.view.inputmethod.InputConnectionCallProto.GetSelectedText;
+import android.view.inputmethod.InputConnectionCallProto.GetSurroundingText;
+import android.view.inputmethod.InputConnectionCallProto.GetTextAfterCursor;
+import android.view.inputmethod.InputConnectionCallProto.GetTextBeforeCursor;
+import android.view.inputmethod.SurroundingText;
+
+/**
+ * Helper class for constructing {@link android.view.inputmethod.InputConnection} dumps, which are
+ * integrated into {@link ImeTracing}.
+ * @hide
+ */
+public class InputConnectionHelper {
+ static final String TAG = "InputConnectionHelper";
+ public static final boolean DUMP_TEXT = false;
+
+ private InputConnectionHelper() {}
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getTextAfterCursor(int, int)} data.
+ *
+ * @param length The expected length of the text. This must be non-negative.
+ * @param flags Supplies additional options controlling how the text is
+ * returned. May be either {@code 0} or
+ * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
+ * @param result The text after the cursor position; the length of the
+ * returned text might be less than <var>length</var>.
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetTextAfterCursorProto(@IntRange(from = 0) int length,
+ int flags, @Nullable CharSequence result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_TEXT_AFTER_CURSOR);
+ proto.write(GetTextAfterCursor.LENGTH, length);
+ proto.write(GetTextAfterCursor.FLAGS, flags);
+ if (result == null) {
+ proto.write(GetTextAfterCursor.RESULT, "null result");
+ } else if (DUMP_TEXT) {
+ proto.write(GetTextAfterCursor.RESULT, result.toString());
+ }
+ proto.end(token);
+ return proto;
+ }
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getTextBeforeCursor(int, int)} data.
+ *
+ * @param length The expected length of the text. This must be non-negative.
+ * @param flags Supplies additional options controlling how the text is
+ * returned. May be either {@code 0} or
+ * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
+ * @param result The text before the cursor position; the length of the
+ * returned text might be less than <var>length</var>.
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetTextBeforeCursorProto(@IntRange(from = 0) int length,
+ int flags, @Nullable CharSequence result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_TEXT_BEFORE_CURSOR);
+ proto.write(GetTextBeforeCursor.LENGTH, length);
+ proto.write(GetTextBeforeCursor.FLAGS, flags);
+ if (result == null) {
+ proto.write(GetTextBeforeCursor.RESULT, "null result");
+ } else if (DUMP_TEXT) {
+ proto.write(GetTextBeforeCursor.RESULT, result.toString());
+ }
+ proto.end(token);
+ return proto;
+ }
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getSelectedText(int)} data.
+ *
+ * @param flags Supplies additional options controlling how the text is
+ * returned. May be either {@code 0} or
+ * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
+ * @param result the text that is currently selected, if any, or null if
+ * no text is selected. In {@link android.os.Build.VERSION_CODES#N} and
+ * later, returns false when the target application does not implement
+ * this method.
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetSelectedTextProto(int flags,
+ @Nullable CharSequence result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_SELECTED_TEXT);
+ proto.write(GetSelectedText.FLAGS, flags);
+ if (result == null) {
+ proto.write(GetSelectedText.RESULT, "null result");
+ } else if (DUMP_TEXT) {
+ proto.write(GetSelectedText.RESULT, result.toString());
+ }
+ proto.end(token);
+ return proto;
+ }
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getSurroundingText(int, int, int)} data.
+ *
+ * @param beforeLength The expected length of the text before the cursor.
+ * @param afterLength The expected length of the text after the cursor.
+ * @param flags Supplies additional options controlling how the text is
+ * returned. May be either {@code 0} or
+ * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
+ * @param result an {@link android.view.inputmethod.SurroundingText} object describing the
+ * surrounding text and state of selection, or null if the input connection is no longer valid,
+ * or the editor can't comply with the request for some reason, or the application does not
+ * implement this method. The length of the returned text might be less than the sum of
+ * <var>beforeLength</var> and <var>afterLength</var> .
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetSurroundingTextProto(@IntRange(from = 0)
+ int beforeLength, @IntRange(from = 0) int afterLength, int flags,
+ @Nullable SurroundingText result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_SURROUNDING_TEXT);
+ proto.write(GetSurroundingText.BEFORE_LENGTH, beforeLength);
+ proto.write(GetSurroundingText.AFTER_LENGTH, afterLength);
+ proto.write(GetSurroundingText.FLAGS, flags);
+ if (result == null) {
+ final long token_result = proto.start(GetSurroundingText.RESULT);
+ proto.write(GetSurroundingText.SurroundingText.TEXT, "null result");
+ proto.end(token_result);
+ } else if (DUMP_TEXT) {
+ final long token_result = proto.start(GetSurroundingText.RESULT);
+ proto.write(GetSurroundingText.SurroundingText.TEXT, result.getText().toString());
+ proto.write(GetSurroundingText.SurroundingText.SELECTION_START,
+ result.getSelectionStart());
+ proto.write(GetSurroundingText.SurroundingText.SELECTION_END,
+ result.getSelectionEnd());
+ proto.write(GetSurroundingText.SurroundingText.OFFSET, result.getOffset());
+ proto.end(token_result);
+ }
+ proto.end(token);
+ return proto;
+ }
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getCursorCapsMode(int)} data.
+ *
+ * @param reqModes The desired modes to retrieve, as defined by
+ * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}.
+ * @param result the caps mode flags that are in effect at the current
+ * cursor position. See TYPE_TEXT_FLAG_CAPS_* in {@link android.text.InputType}.
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetCursorCapsModeProto(int reqModes, int result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_CURSOR_CAPS_MODE);
+ proto.write(GetCursorCapsMode.REQ_MODES, reqModes);
+ if (DUMP_TEXT) {
+ proto.write(GetCursorCapsMode.RESULT, result);
+ }
+ proto.end(token);
+ return proto;
+ }
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getExtractedText(ExtractedTextRequest, int)}
+ * data.
+ *
+ * @param request Description of how the text should be returned.
+ * {@link android.view.inputmethod.ExtractedTextRequest}
+ * @param flags Additional options to control the client, either {@code 0} or
+ * {@link android.view.inputmethod.InputConnection#GET_EXTRACTED_TEXT_MONITOR}.
+ * @param result an {@link android.view.inputmethod.ExtractedText}
+ * object describing the state of the text view and containing the
+ * extracted text itself, or null if the input connection is no
+ * longer valid of the editor can't comply with the request for
+ * some reason.
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetExtractedTextProto(@NonNull ExtractedTextRequest
+ request, int flags, @Nullable ExtractedText result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_EXTRACTED_TEXT);
+ final long token_request = proto.start(REQUEST);
+ proto.write(GetExtractedText.ExtractedTextRequest.TOKEN, request.token);
+ proto.write(GetExtractedText.ExtractedTextRequest.FLAGS, request.flags);
+ proto.write(GetExtractedText.ExtractedTextRequest.HINT_MAX_LINES, request.hintMaxLines);
+ proto.write(GetExtractedText.ExtractedTextRequest.HINT_MAX_CHARS, request.hintMaxChars);
+ proto.end(token_request);
+ proto.write(GetExtractedText.FLAGS, flags);
+ if (result == null) {
+ proto.write(GetExtractedText.RESULT, "null result");
+ } else if (DUMP_TEXT) {
+ proto.write(GetExtractedText.RESULT, result.text.toString());
+ }
+ proto.end(token);
+ return proto;
+ }
+}
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 2f1e2ded26ac..6488490b8863 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -19,7 +19,11 @@ package android.uwb;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.IBinder;
import android.os.PersistableBundle;
+import android.os.ServiceManager;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -36,7 +40,11 @@ import java.util.concurrent.Executor;
*
* @hide
*/
+@SystemService(Context.UWB_SERVICE)
public final class UwbManager {
+ private IUwbAdapter mUwbAdapter;
+ private static final String SERVICE_NAME = "uwb";
+
/**
* Interface for receiving UWB adapter state changes
*/
@@ -96,10 +104,30 @@ public final class UwbManager {
/**
* Use <code>Context.getSystemService(UwbManager.class)</code> to get an instance.
+ *
+ * @param adapter an instance of an {@link android.uwb.IUwbAdapter}
*/
- private UwbManager() {
- throw new UnsupportedOperationException();
+ private UwbManager(IUwbAdapter adapter) {
+ mUwbAdapter = adapter;
+ }
+
+ /**
+ * @hide
+ */
+ public static UwbManager getInstance() {
+ IBinder b = ServiceManager.getService(SERVICE_NAME);
+ if (b == null) {
+ return null;
+ }
+
+ IUwbAdapter adapter = IUwbAdapter.Stub.asInterface(b);
+ if (adapter == null) {
+ return null;
+ }
+
+ return new UwbManager(adapter);
}
+
/**
* Register an {@link AdapterStateCallback} to listen for UWB adapter state changes
* <p>The provided callback will be invoked by the given {@link Executor}.
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 56c7e27151e0..9991367e6bfd 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1512,6 +1512,9 @@ public final class Display {
* then 1920x1080 50Hz will have alternative refresh rate of 60Hz. If 1920x1080 60Hz
* has an alternative of 50Hz and 1920x1080 50Hz has an alternative of 24Hz, then 1920x1080
* 60Hz will also have an alternative of 24Hz.
+ *
+ * @see Surface#setFrameRate
+ * @see SurfaceControl.Transaction#setFrameRate
*/
@NonNull
public float[] getAlternativeRefreshRates() {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 1c82619a61ad..c4f32c433598 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -829,7 +829,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("InsetsController#show",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0);
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
} else {
@@ -886,7 +886,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
void hide(@InsetsType int types, boolean fromIme) {
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("InsetsController#hide",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
} else {
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
@@ -928,7 +928,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (fromIme) {
ImeTracing.getInstance().triggerClientDump(
"InsetsController#controlWindowInsetsAnimation",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
}
controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
@@ -1022,7 +1022,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
animationType, mHost.getTranslator());
if ((typesReady & WindowInsets.Type.ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsAnimationControlImpl",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
}
mRunningAnimations.add(new RunningAnimation(runner, animationType));
if (DEBUG) Log.d(TAG, "Animation added to runner. useInsetsAnimationThread: "
@@ -1200,7 +1200,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (types.valueAt(j) == ITYPE_IME) {
ImeTracing.getInstance().triggerClientDump(
"InsetsSourceConsumer#notifyAnimationFinished",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
}
stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
}
@@ -1345,7 +1345,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
boolean fromIme) {
if ((types & ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsController#hideDirectly",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
}
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
@@ -1361,7 +1361,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private void showDirectly(@InsetsType int types, boolean fromIme) {
if ((types & ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsController#showDirectly",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
}
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 57ca71ae4b02..d839e3532b64 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.FrameInfo;
import android.graphics.HardwareRenderer;
import android.graphics.Picture;
import android.graphics.Point;
@@ -610,8 +611,7 @@ public final class ThreadedRenderer extends HardwareRenderer {
* @param attachInfo AttachInfo tied to the specified view.
*/
void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
- final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
- choreographer.mFrameInfo.markDrawStart();
+ attachInfo.mViewRootImpl.mViewFrameInfo.markDrawStart();
updateRootDisplayList(view, callbacks);
@@ -629,7 +629,9 @@ public final class ThreadedRenderer extends HardwareRenderer {
attachInfo.mPendingAnimatingRenderNodes = null;
}
- int syncResult = syncAndDrawFrame(choreographer.mFrameInfo);
+ final FrameInfo frameInfo = attachInfo.mViewRootImpl.getUpdatedFrameInfo();
+
+ int syncResult = syncAndDrawFrame(frameInfo);
if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
Log.w("OpenGLRenderer", "Surface lost, forcing relayout");
// We lost our surface. For a relayout next frame which should give us a new
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a5c66537b11f..29cc4b507acc 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27953,10 +27953,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Requests pointer capture mode.
* <p>
* When the window has pointer capture, the mouse pointer icon will disappear and will not
- * change its position. Further mouse will be dispatched with the source
- * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available
- * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events
- * (touchscreens, or stylus) will not be affected.
+ * change its position. Enabling pointer capture will change the behavior of input devices in
+ * the following ways:
+ * <ul>
+ * <li>Events from a mouse will be delivered with the source
+ * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be
+ * available through {@link MotionEvent#getX} and {@link MotionEvent#getY}.</li>
+ *
+ * <li>Events from a touchpad will be delivered with the source
+ * {@link InputDevice#SOURCE_TOUCHPAD}, where the absolute position of each of the pointers
+ * on the touchpad will be available through {@link MotionEvent#getX(int)} and
+ * {@link MotionEvent#getY(int)}, and their relative movements are stored in
+ * {@link MotionEvent#AXIS_RELATIVE_X} and {@link MotionEvent#AXIS_RELATIVE_Y}.</li>
+ *
+ * <li>Events from other types of devices, such as touchscreens, will not be affected.</li>
+ * </ul>
+ * <p>
+ * Events captured through pointer capture will be dispatched to
+ * {@link OnCapturedPointerListener#onCapturedPointer(View, MotionEvent)} if an
+ * {@link OnCapturedPointerListener} is set, and otherwise to
+ * {@link #onCapturedPointerEvent(MotionEvent)}.
* <p>
* If the window already has pointer capture, this call does nothing.
* <p>
@@ -27965,6 +27981,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @see #releasePointerCapture()
* @see #hasPointerCapture()
+ * @see #onPointerCaptureChange(boolean)
*/
public void requestPointerCapture() {
final ViewRootImpl viewRootImpl = getViewRootImpl();
@@ -27980,6 +27997,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* If the window does not have pointer capture, this call will do nothing.
* @see #requestPointerCapture()
* @see #hasPointerCapture()
+ * @see #onPointerCaptureChange(boolean)
*/
public void releasePointerCapture() {
final ViewRootImpl viewRootImpl = getViewRootImpl();
diff --git a/core/java/android/view/ViewFrameInfo.java b/core/java/android/view/ViewFrameInfo.java
new file mode 100644
index 000000000000..890d071f8090
--- /dev/null
+++ b/core/java/android/view/ViewFrameInfo.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import android.graphics.FrameInfo;
+
+/**
+ * The timing information of events taking place in ViewRootImpl
+ * @hide
+ */
+public class ViewFrameInfo {
+ public long drawStart;
+ public long oldestInputEventTime; // the time of the oldest input event consumed for this frame
+ public long newestInputEventTime; // the time of the newest input event consumed for this frame
+ // Various flags set to provide extra metadata about the current frame. See flag definitions
+ // inside FrameInfo.
+ // @see android.graphics.FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED
+ public long flags;
+
+ /**
+ * Update the oldest event time.
+ * @param eventTime the time of the input event
+ */
+ public void updateOldestInputEvent(long eventTime) {
+ if (oldestInputEventTime == 0 || eventTime < oldestInputEventTime) {
+ oldestInputEventTime = eventTime;
+ }
+ }
+
+ /**
+ * Update the newest event time.
+ * @param eventTime the time of the input event
+ */
+ public void updateNewestInputEvent(long eventTime) {
+ if (newestInputEventTime == 0 || eventTime > newestInputEventTime) {
+ newestInputEventTime = eventTime;
+ }
+ }
+
+ /**
+ * Populate the missing fields using the data from ViewFrameInfo
+ * @param frameInfo : the structure FrameInfo object to populate
+ */
+ public void populateFrameInfo(FrameInfo frameInfo) {
+ frameInfo.frameInfo[FrameInfo.FLAGS] |= flags;
+ frameInfo.frameInfo[FrameInfo.DRAW_START] = drawStart;
+ frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT] = oldestInputEventTime;
+ frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT] = newestInputEventTime;
+ }
+
+ /**
+ * Reset this data. Should typically be invoked after calling "populateFrameInfo".
+ */
+ public void reset() {
+ drawStart = 0;
+ oldestInputEventTime = 0;
+ newestInputEventTime = 0;
+ flags = 0;
+ }
+
+ /**
+ * Record the current time, and store it in 'drawStart'
+ */
+ public void markDrawStart() {
+ drawStart = System.nanoTime();
+ }
+}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2bea0d6b4b04..a274079d0108 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -423,7 +423,7 @@ public final class ViewRootImpl implements ViewParent,
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
int mHeight;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- Rect mDirty;
+ private Rect mDirty;
public boolean mIsAnimating;
private boolean mUseMTRenderer;
@@ -446,6 +446,23 @@ public final class ViewRootImpl implements ViewParent,
@UnsupportedAppUsage
FallbackEventHandler mFallbackEventHandler;
final Choreographer mChoreographer;
+ protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo();
+
+ /**
+ * Update the Choreographer's FrameInfo object with the timing information for the current
+ * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next
+ * frame.
+ * @return the updated FrameInfo object
+ */
+ protected @NonNull FrameInfo getUpdatedFrameInfo() {
+ // Since Choreographer is a thread-local singleton while we can have multiple
+ // ViewRootImpl's, populate the frame information from the current viewRootImpl before
+ // starting the draw
+ FrameInfo frameInfo = mChoreographer.mFrameInfo;
+ mViewFrameInfo.populateFrameInfo(frameInfo);
+ mViewFrameInfo.reset();
+ return frameInfo;
+ }
// used in relayout to get SurfaceControl size
// for BLAST adapter surface setup
@@ -2675,7 +2692,7 @@ public final class ViewRootImpl implements ViewParent,
// to resume them
mDirty.set(0, 0, mWidth, mHeight);
}
- mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
+ mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED;
}
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
@@ -8138,7 +8155,8 @@ public final class ViewRootImpl implements ViewParent,
oldestEventTime = me.getHistoricalEventTimeNano(0);
}
}
- mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
+ mViewFrameInfo.updateOldestInputEvent(oldestEventTime);
+ mViewFrameInfo.updateNewestInputEvent(eventTime);
deliverInputEvent(q);
}
@@ -9225,7 +9243,8 @@ public final class ViewRootImpl implements ViewParent,
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#showInsets",
- viewAncestor.getInsetsController().getHost().getInputMethodManager());
+ viewAncestor.getInsetsController().getHost().getInputMethodManager(),
+ null /* icProto */);
}
if (viewAncestor != null) {
viewAncestor.showInsets(types, fromIme);
@@ -9238,7 +9257,8 @@ public final class ViewRootImpl implements ViewParent,
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#hideInsets",
- viewAncestor.getInsetsController().getHost().getInputMethodManager());
+ viewAncestor.getInsetsController().getHost().getInputMethodManager(),
+ null /* icProto */);
}
if (viewAncestor != null) {
viewAncestor.hideInsets(types, fromIme);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 8d2c2d96637f..907b5b085b59 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -23,6 +23,7 @@ import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodCl
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.EDITOR_INFO;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_INSETS_SOURCE_CONSUMER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION_CALL;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_METHOD_MANAGER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.VIEW_ROOT_IMPL;
import static android.view.inputmethod.InputMethodManagerProto.ACTIVE;
@@ -579,7 +580,8 @@ public final class InputMethodManager {
int windowFlags) {
final View servedView;
ImeTracing.getInstance().triggerClientDump(
- "InputMethodManager.DelegateImpl#startInput", InputMethodManager.this);
+ "InputMethodManager.DelegateImpl#startInput", InputMethodManager.this,
+ null /* icProto */);
synchronized (mH) {
mCurrentTextBoxAttribute = null;
mCompletions = null;
@@ -1016,6 +1018,11 @@ public final class InputMethodManager {
return mParentInputMethodManager.mActive && !isFinished();
}
+ @Override
+ public InputMethodManager getIMM() {
+ return mParentInputMethodManager;
+ }
+
void deactivate() {
if (isFinished()) {
// This is a small performance optimization. Still only the 1st call of
@@ -1713,7 +1720,8 @@ public final class InputMethodManager {
* {@link #RESULT_HIDDEN}.
*/
public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
- ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this);
+ ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this,
+ null /* icProto */);
// Re-dispatch if there is a context mismatch.
final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
if (fallbackImm != null) {
@@ -1822,7 +1830,7 @@ public final class InputMethodManager {
public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
ResultReceiver resultReceiver) {
ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow",
- this);
+ this, null /* icProto */);
checkFocus();
synchronized (mH) {
final View servedView = getServedViewLocked();
@@ -2228,7 +2236,8 @@ public final class InputMethodManager {
* @hide
*/
public void notifyImeHidden(IBinder windowToken) {
- ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this);
+ ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
+ null /* icProto */);
synchronized (mH) {
try {
if (mCurMethod != null && mCurRootView != null
@@ -3296,7 +3305,7 @@ public final class InputMethodManager {
for (String arg : args) {
if (arg.equals(PROTO_ARG)) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
- dumpDebug(proto);
+ dumpDebug(proto, null /* icProto */);
proto.flush();
return true;
}
@@ -3309,10 +3318,11 @@ public final class InputMethodManager {
* {@link ProtoOutputStream}.
*
* @param proto The proto stream to which the dumps are written.
+ * @param icProto {@link InputConnection} call data in proto format.
* @hide
*/
@GuardedBy("mH")
- public void dumpDebug(ProtoOutputStream proto) {
+ public void dumpDebug(ProtoOutputStream proto, ProtoOutputStream icProto) {
if (mCurMethod == null) {
return;
}
@@ -3337,6 +3347,9 @@ public final class InputMethodManager {
if (mServedInputConnectionWrapper != null) {
mServedInputConnectionWrapper.dumpDebug(proto, INPUT_CONNECTION);
}
+ if (icProto != null) {
+ proto.write(INPUT_CONNECTION_CALL, icProto.getBytes());
+ }
}
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2357f368c428..02a930017906 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -964,6 +964,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @hide
*/
public static void preloadFontCache() {
+ if (Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+ return;
+ }
Paint p = new Paint();
p.setAntiAlias(true);
// Ensure that the Typeface is loaded here.
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 2e3d560ccb56..9668c3b0af1c 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -162,6 +162,9 @@ public class ChooserActivity extends ResolverActivity implements
private AppPredictor mWorkAppPredictor;
private boolean mShouldDisplayLandscape;
+ private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4;
+ private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8;
+
@UnsupportedAppUsage
public ChooserActivity() {
}
@@ -905,7 +908,7 @@ public class ChooserActivity extends ResolverActivity implements
adapter,
getPersonalProfileUserHandle(),
/* workProfileUserHandle= */ null,
- isSendAction(getTargetIntent()));
+ isSendAction(getTargetIntent()), getMaxTargetsPerRow());
}
private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles(
@@ -934,7 +937,7 @@ public class ChooserActivity extends ResolverActivity implements
selectedProfile,
getPersonalProfileUserHandle(),
getWorkProfileUserHandle(),
- isSendAction(getTargetIntent()));
+ isSendAction(getTargetIntent()), getMaxTargetsPerRow());
}
private int findSelectedProfile() {
@@ -2683,7 +2686,7 @@ public class ChooserActivity extends ResolverActivity implements
// and b/150936654
recyclerView.setAdapter(gridAdapter);
((GridLayoutManager) recyclerView.getLayoutManager()).setSpanCount(
- gridAdapter.getMaxTargetsPerRow());
+ getMaxTargetsPerRow());
}
UserHandle currentUserHandle = mChooserMultiProfilePagerAdapter.getCurrentUserHandle();
@@ -2848,9 +2851,7 @@ public class ChooserActivity extends ResolverActivity implements
@Override // ChooserListCommunicator
public int getMaxRankedTargets() {
- return mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() == null
- ? ChooserGridAdapter.MAX_TARGETS_PER_ROW_PORTRAIT
- : mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().getMaxTargetsPerRow();
+ return getMaxTargetsPerRow();
}
@Override // ChooserListCommunicator
@@ -3198,6 +3199,13 @@ public class ChooserActivity extends ResolverActivity implements
}
}
+ int getMaxTargetsPerRow() {
+ int maxTargets = MAX_TARGETS_PER_ROW_PORTRAIT;
+ if (mShouldDisplayLandscape) {
+ maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE;
+ }
+ return maxTargets;
+ }
/**
* Adapter for all types of items and targets in ShareSheet.
* Note that ranked sections like Direct Share - while appearing grid-like - are handled on the
@@ -3226,9 +3234,6 @@ public class ChooserActivity extends ResolverActivity implements
private static final int VIEW_TYPE_CALLER_AND_RANK = 5;
private static final int VIEW_TYPE_FOOTER = 6;
- private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4;
- private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8;
-
private static final int NUM_EXPANSIONS_TO_HIDE_AZ_LABEL = 20;
ChooserGridAdapter(ChooserListAdapter wrappedAdapter) {
@@ -3277,14 +3282,6 @@ public class ChooserActivity extends ResolverActivity implements
return false;
}
- int getMaxTargetsPerRow() {
- int maxTargets = MAX_TARGETS_PER_ROW_PORTRAIT;
- if (mShouldDisplayLandscape) {
- maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE;
- }
- return maxTargets;
- }
-
/**
* Hides the list item content preview.
* <p>Not to be confused with the sticky content preview which is above the
@@ -3654,8 +3651,7 @@ public class ChooserActivity extends ResolverActivity implements
position -= getSystemRowCount() + getProfileRowCount();
final int serviceCount = mChooserListAdapter.getServiceTargetCount();
- final int serviceRows = (int) Math.ceil((float) serviceCount
- / ChooserListAdapter.MAX_SERVICE_TARGETS);
+ final int serviceRows = (int) Math.ceil((float) serviceCount / getMaxRankedTargets());
if (position < serviceRows) {
return position * getMaxTargetsPerRow();
}
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index 00b5cb646bca..570066807f16 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -82,8 +82,6 @@ public class ChooserListAdapter extends ResolverListAdapter {
private static final int MAX_SERVICE_TARGET_APP = 8;
private static final int DEFAULT_DIRECT_SHARE_RANKING_SCORE = 1000;
- static final int MAX_SERVICE_TARGETS = 8;
-
/** {@link #getBaseScore} */
public static final float CALLER_TARGET_SCORE_BOOST = 900.f;
/** {@link #getBaseScore} */
@@ -130,10 +128,10 @@ public class ChooserListAdapter extends ResolverListAdapter {
super(context, payloadIntents, null, rList, filterLastUsed,
resolverListController, chooserListCommunicator, false);
- createPlaceHolders();
mMaxShortcutTargetsPerApp =
context.getResources().getInteger(R.integer.config_maxShortcutTargetsPerApp);
mChooserListCommunicator = chooserListCommunicator;
+ createPlaceHolders();
mSelectableTargetInfoCommunicator = selectableTargetInfoCommunicator;
if (initialIntents != null) {
@@ -227,7 +225,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
mParkingDirectShareTargets.clear();
mPendingChooserTargetService.clear();
mShortcutComponents.clear();
- for (int i = 0; i < MAX_SERVICE_TARGETS; i++) {
+ for (int i = 0; i < mChooserListCommunicator.getMaxRankedTargets(); i++) {
mServiceTargets.add(mPlaceHolderTargetInfo);
}
}
@@ -382,7 +380,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
public int getServiceTargetCount() {
if (mChooserListCommunicator.isSendAction(mChooserListCommunicator.getTargetIntent())
&& !ActivityManager.isLowRamDeviceStatic()) {
- return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS);
+ return Math.min(mServiceTargets.size(), mChooserListCommunicator.getMaxRankedTargets());
}
return 0;
@@ -847,7 +845,8 @@ public class ChooserListAdapter extends ResolverListAdapter {
int currentSize = mServiceTargets.size();
final float newScore = chooserTargetInfo.getModifiedScore();
- for (int i = 0; i < Math.min(currentSize, MAX_SERVICE_TARGETS); i++) {
+ for (int i = 0; i < Math.min(currentSize, mChooserListCommunicator.getMaxRankedTargets());
+ i++) {
final ChooserTargetInfo serviceTarget = mServiceTargets.get(i);
if (serviceTarget == null) {
mServiceTargets.set(i, chooserTargetInfo);
@@ -858,7 +857,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
}
}
- if (currentSize < MAX_SERVICE_TARGETS) {
+ if (currentSize < mChooserListCommunicator.getMaxRankedTargets()) {
mServiceTargets.add(chooserTargetInfo);
return true;
}
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 3a65a324f9d6..dd837fc2194c 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -39,17 +39,19 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
private final ChooserProfileDescriptor[] mItems;
private final boolean mIsSendAction;
private int mBottomOffset;
+ private int mMaxTargetsPerRow;
ChooserMultiProfilePagerAdapter(Context context,
ChooserActivity.ChooserGridAdapter adapter,
UserHandle personalProfileUserHandle,
UserHandle workProfileUserHandle,
- boolean isSendAction) {
+ boolean isSendAction, int maxTargetsPerRow) {
super(context, /* currentPage */ 0, personalProfileUserHandle, workProfileUserHandle);
mItems = new ChooserProfileDescriptor[] {
createProfileDescriptor(adapter)
};
mIsSendAction = isSendAction;
+ mMaxTargetsPerRow = maxTargetsPerRow;
}
ChooserMultiProfilePagerAdapter(Context context,
@@ -58,7 +60,7 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
@Profile int defaultProfile,
UserHandle personalProfileUserHandle,
UserHandle workProfileUserHandle,
- boolean isSendAction) {
+ boolean isSendAction, int maxTargetsPerRow) {
super(context, /* currentPage */ defaultProfile, personalProfileUserHandle,
workProfileUserHandle);
mItems = new ChooserProfileDescriptor[] {
@@ -66,6 +68,7 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
createProfileDescriptor(workAdapter)
};
mIsSendAction = isSendAction;
+ mMaxTargetsPerRow = maxTargetsPerRow;
}
private ChooserProfileDescriptor createProfileDescriptor(
@@ -114,7 +117,7 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
ChooserActivity.ChooserGridAdapter chooserGridAdapter =
getItem(pageIndex).chooserGridAdapter;
GridLayoutManager glm = (GridLayoutManager) recyclerView.getLayoutManager();
- glm.setSpanCount(chooserGridAdapter.getMaxTargetsPerRow());
+ glm.setSpanCount(mMaxTargetsPerRow);
glm.setSpanSizeLookup(
new GridLayoutManager.SpanSizeLookup() {
@Override
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 4deb40a0d772..1d5935db6322 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -27,6 +27,9 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
+import android.util.imetracing.ImeTracing;
+import android.util.imetracing.InputConnectionHelper;
+import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -36,6 +39,7 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionInspector;
import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
import android.view.inputmethod.InputContentInfo;
+import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.SurroundingText;
import com.android.internal.annotations.GuardedBy;
@@ -124,7 +128,9 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
}
- abstract protected boolean isActive();
+ protected abstract boolean isActive();
+
+ protected abstract InputMethodManager getIMM();
public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback));
@@ -264,6 +270,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
void executeMessage(Message msg) {
+ ProtoOutputStream icProto;
switch (msg.what) {
case DO_GET_TEXT_AFTER_CURSOR: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
@@ -278,6 +285,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getTextAfterCursor(msg.arg1, msg.arg2);
}
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetTextAfterCursorProto(msg.arg1,
+ msg.arg2, result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getTextAfterCursor", getIMM(), icProto);
+ }
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -302,6 +315,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getTextBeforeCursor(msg.arg1, msg.arg2);
}
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(msg.arg1,
+ msg.arg2, result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getTextBeforeCursor", getIMM(), icProto);
+ }
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -326,6 +345,11 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getSelectedText(msg.arg1);
}
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetSelectedTextProto(msg.arg1, result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getSelectedText", getIMM(), icProto);
+ }
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -354,6 +378,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getSurroundingText(beforeLength, afterLength, flags);
}
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetSurroundingTextProto(beforeLength,
+ afterLength, flags, result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getSurroundingText", getIMM(), icProto);
+ }
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -378,6 +408,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getCursorCapsMode(msg.arg1);
}
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetCursorCapsModeProto(msg.arg1,
+ result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getCursorCapsMode", getIMM(), icProto);
+ }
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -404,6 +440,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getExtractedText(request, msg.arg1);
}
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetExtractedTextProto(request,
+ msg.arg1, result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getExtractedText", getIMM(), icProto);
+ }
try {
callback.onResult(result);
} catch (RemoteException e) {
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 8c763a6efe54..b70348a95384 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -24,6 +24,9 @@ import android.inputmethodservice.AbstractInputMethodService;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
+import android.util.imetracing.ImeTracing;
+import android.util.imetracing.InputConnectionHelper;
+import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -87,8 +90,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
- return Completable.getResultOrNull(
+ CharSequence result = Completable.getResultOrNull(
value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetTextAfterCursorProto(length,
+ flags, result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextAfterCursor",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
/**
@@ -107,8 +120,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
- return Completable.getResultOrNull(
+ CharSequence result = Completable.getResultOrNull(
value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(length,
+ flags, result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextBeforeCursor",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
@AnyThread
@@ -127,8 +150,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
- return Completable.getResultOrNull(
+ CharSequence result = Completable.getResultOrNull(
value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetSelectedTextProto(flags,
+ result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getSelectedText",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
/**
@@ -161,8 +194,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
- return Completable.getResultOrNull(
+ SurroundingText result = Completable.getResultOrNull(
value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetSurroundingTextProto(
+ beforeLength, afterLength, flags, result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getSurroundingText",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
@AnyThread
@@ -177,8 +220,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return 0;
}
- return Completable.getResultOrZero(
+ int result = Completable.getResultOrZero(
value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetCursorCapsModeProto(
+ reqModes, result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getCursorCapsMode",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
@AnyThread
@@ -193,8 +246,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
- return Completable.getResultOrNull(
+ ExtractedText result = Completable.getResultOrNull(
value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetExtractedTextProto(
+ request, flags, result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getExtractedText",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
@AnyThread
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index d30d662806d4..6cdf0df17b65 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -28,6 +28,7 @@ import android.text.Editable;
import android.text.Selection;
import android.text.method.KeyListener;
import android.util.Log;
+import android.util.imetracing.InputConnectionHelper;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
@@ -45,7 +46,6 @@ import android.widget.TextView;
public class EditableInputConnection extends BaseInputConnection
implements DumpableInputConnection {
private static final boolean DEBUG = false;
- private static final boolean DUMP_TEXT = false;
private static final String TAG = "EditableInputConnection";
private final TextView mTextView;
@@ -243,7 +243,7 @@ public class EditableInputConnection extends BaseInputConnection
final long token = proto.start(fieldId);
CharSequence editableText = mTextView.getText();
CharSequence selectedText = getSelectedText(0 /* flags */);
- if (DUMP_TEXT) {
+ if (InputConnectionHelper.DUMP_TEXT) {
if (editableText != null) {
proto.write(EDITABLE_TEXT, editableText.toString());
}
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 4ddc782aacb4..bad21d28416b 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -1090,6 +1090,20 @@ public class LockPatternView extends View {
}
}
+ /**
+ * Change theme colors
+ * @param regularColor The dot color
+ * @param successColor Color used when pattern is correct
+ * @param errorColor Color used when authentication fails
+ */
+ public void setColors(int regularColor, int successColor, int errorColor) {
+ mRegularColor = regularColor;
+ mErrorColor = errorColor;
+ mSuccessColor = successColor;
+ mPathPaint.setColor(regularColor);
+ invalidate();
+ }
+
private float getCenterXForColumn(int column) {
return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f;
}
diff --git a/core/proto/android/inputmethodservice/inputmethodservice.proto b/core/proto/android/inputmethodservice/inputmethodservice.proto
index e5d171361695..1f68fb4b513d 100644
--- a/core/proto/android/inputmethodservice/inputmethodservice.proto
+++ b/core/proto/android/inputmethodservice/inputmethodservice.proto
@@ -18,6 +18,7 @@ syntax = "proto2";
import "frameworks/base/core/proto/android/inputmethodservice/softinputwindow.proto";
import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
+import "frameworks/base/core/proto/android/view/inputmethod/inputconnection.proto";
package android.inputmethodservice;
@@ -51,6 +52,7 @@ message InputMethodServiceProto {
optional int32 status_icon = 25;
optional InsetsProto last_computed_insets = 26;
optional string settings_observer = 27;
+ optional .android.view.inputmethod.InputConnectionCallProto input_connection_call = 28;
message InsetsProto {
optional int32 content_top_insets = 1;
diff --git a/core/proto/android/view/inputmethod/inputconnection.proto b/core/proto/android/view/inputmethod/inputconnection.proto
index ad9a95aa95e6..d1f257ff2c5c 100644
--- a/core/proto/android/view/inputmethod/inputconnection.proto
+++ b/core/proto/android/view/inputmethod/inputconnection.proto
@@ -31,4 +31,68 @@ message InputConnectionProto {
optional int32 selected_text_start = 3;
optional int32 selected_text_end = 4;
optional int32 cursor_caps_mode = 5;
+}
+
+/**
+ * Shows information about parameters and result for method calls to
+ * {@link android.view.inputmethod.InputConnection}.
+ */
+message InputConnectionCallProto {
+ oneof method_call {
+ GetTextBeforeCursor get_text_before_cursor = 1;
+ GetTextAfterCursor get_text_after_cursor = 2;
+ GetSelectedText get_selected_text = 3;
+ GetSurroundingText get_surrounding_text = 4;
+ GetCursorCapsMode get_cursor_caps_mode = 5;
+ GetExtractedText get_extracted_text = 6;
+ }
+
+ message GetTextBeforeCursor {
+ optional int32 length = 1;
+ optional int32 flags = 2;
+ optional string result = 3 [(.android.privacy).dest = DEST_LOCAL];
+ }
+
+ message GetTextAfterCursor {
+ optional int32 length = 1;
+ optional int32 flags = 2;
+ optional string result = 3 [(.android.privacy).dest = DEST_LOCAL];
+ }
+
+ message GetSelectedText {
+ optional int32 flags = 1;
+ optional string result = 2 [(.android.privacy).dest = DEST_LOCAL];
+ }
+
+ message GetSurroundingText {
+ optional int32 before_length = 1;
+ optional int32 after_length = 2;
+ optional int32 flags = 3;
+ optional SurroundingText result = 4;
+
+ message SurroundingText {
+ optional string text = 1 [(.android.privacy).dest = DEST_LOCAL];
+ optional int32 selection_start = 2;
+ optional int32 selection_end = 3;
+ optional int32 offset = 4;
+ }
+ }
+
+ message GetCursorCapsMode {
+ optional int32 req_modes = 1;
+ optional int32 result = 2;
+ }
+
+ message GetExtractedText {
+ optional ExtractedTextRequest request = 1;
+ optional int32 flags = 2;
+ optional string result = 3 [(.android.privacy).dest = DEST_LOCAL];
+
+ message ExtractedTextRequest {
+ optional int32 token = 1;
+ optional int32 flags = 2;
+ optional int32 hint_max_lines = 3;
+ optional int32 hint_max_chars = 4;
+ }
+ }
} \ No newline at end of file
diff --git a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
index c1dce6f2d093..8e4377ca124c 100644
--- a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
+++ b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
@@ -72,6 +72,7 @@ message InputMethodClientsTraceProto {
optional EditorInfoProto editor_info = 6;
optional ImeFocusControllerProto ime_focus_controller = 7;
optional InputConnectionProto input_connection = 8;
+ optional InputConnectionCallProto input_connection_call = 9;
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 60dd0eb8a780..1250eb776176 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4047,6 +4047,13 @@
<permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS"
android:protectionLevel="signature" />
+ <!-- Allows an application to modify the refresh rate switching type. This
+ matches Setting.Secure.MATCH_CONTENT_FRAME_RATE.
+ @hide
+ @TestApi -->
+ <permission android:name="android.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to control VPN.
<p>Not for use by third-party applications.</p>
@hide -->
@@ -5255,7 +5262,8 @@
<attribution android:tag="TwilightService" android:label="@string/twilight_service"/>
<!-- Attribution for the Offline LocationTimeZoneProvider, used to detect time zone using
on-device data -->
- <attribution android:tag="OfflineLocationTimeZoneProvider" android:label="@string/offline_location_time_zone_detection_service"/>
+ <attribution android:tag="OfflineLocationTimeZoneProvider"
+ android:label="@string/offline_location_time_zone_detection_service_attribution"/>
<application android:process="system"
android:persistent="true"
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 39cdce9cc46b..29f2b6f14b57 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -26,9 +26,6 @@
<color name="notification_default_color_dark">#ddffffff</color>
- <!-- The background color of a notification card. -->
- <color name="notification_material_background_color">@color/black</color>
-
<color name="chooser_row_divider">@color/list_divider_color_dark</color>
<color name="chooser_gradient_background">@color/loading_gradient_background_color_dark</color>
<color name="chooser_gradient_highlight">@color/loading_gradient_highlight_color_dark</color>
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index 4e6b712f1f5d..952cdd08451c 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -25,18 +25,12 @@
<item name="colorControlNormal">?attr/textColorPrimary</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
<item name="forceDarkAllowed">false</item>
-
- <!-- QS panel background -->
- <item name="colorBackgroundFloating">@color/black</item>
-
- <!-- volume background -->
- <item name="panelColorBackground">@color/material_grey_800</item>
</style>
<style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Dialog" />
<style name="TextAppearance.Material.Notification">
- <item name="textColor">@color/notification_secondary_text_color_dark</item>
+ <item name="textColor">?attr/textColorPrimary</item>
<item name="textSize">@dimen/notification_text_size</item>
</style>
</resources> \ No newline at end of file
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 1242c6dc8217..0079d8cd0276 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -143,8 +143,6 @@
<color name="notification_default_color_dark">@color/primary_text_default_material_light</color>
<color name="notification_default_color_light">#a3202124</color>
- <color name="notification_material_background_color">#ffffffff</color>
-
<color name="notification_default_color">#757575</color> <!-- Gray 600 -->
<color name="notification_action_button_text_color">@color/notification_default_color</color>
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 7a8f411992ce..310ca893ac39 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -37,10 +37,10 @@
<color name="accent_device_default_dark">@color/accent_material_dark</color>
<color name="accent_device_default">@color/accent_device_default_light</color>
- <color name="background_device_default_dark">@color/background_material_dark</color>
- <color name="background_device_default_light">@color/background_material_light</color>
- <color name="background_floating_device_default_dark">@color/background_floating_material_dark</color>
- <color name="background_floating_device_default_light">@color/background_floating_material_light</color>
+ <color name="background_device_default_dark">#1A1A1A</color>
+ <color name="background_device_default_light">#F2F2F2</color>
+ <color name="background_floating_device_default_dark">#0D0D0D</color>
+ <color name="background_floating_device_default_light">#CCCCCC</color>
<!-- Error color -->
<color name="error_color_device_default_dark">@color/error_color_material_dark</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f8cbfebabdcf..84e6f12c0b51 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1559,6 +1559,14 @@
<!-- Class name of WallpaperManagerService. -->
<string name="config_wallpaperManagerServiceName" translatable="false">com.android.server.wallpaper.WallpaperManagerService</string>
+ <!-- Specifies priority of automatic time sources. Suggestions from higher entries in the list
+ take precedence over lower ones.
+ See com.android.server.timedetector.TimeDetectorStrategy for available sources. -->
+ <string-array name="config_autoTimeSourcesPriority">
+ <item>telephony</item>
+ <item>network</item>
+ </string-array>
+
<!-- Enables the TimeZoneRuleManager service. This is the global switch for the updateable time
zone update mechanism. -->
<bool name="config_enableUpdateableTimeZoneRules">false</bool>
@@ -4554,4 +4562,7 @@
<!-- Indicates that default fitness tracker app needs to request sensor and location permissions. -->
<bool name="config_trackerAppNeedsPermissions">false</bool>
+
+ <!-- Component with platform query permissions for AppSearch -->
+ <string name="config_defaultAppSearchPlatformQuerierComponent" translatable="false"></string>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8e3a0cbdd10c..89b986b8fcb8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -433,9 +433,12 @@
<string name="sensor_notification_service">Sensor Notification Service</string>
<!-- Attribution for Twilight service. [CHAR LIMIT=NONE]-->
<string name="twilight_service">Twilight Service</string>
- <!-- Attribution for Offline LocationTimeZoneDetector service, i.e. one capable of performing
- time zone lookup using geo-spacial information held on the device. [CHAR LIMIT=NONE]-->
- <string name="offline_location_time_zone_detection_service">Offline Time Zone Detection Service</string>
+ <!-- Attribution for the Offline LocationTimeZoneProvider service, i.e. the service capable of
+ performing time zone detection using time zone geospatial information held on the device.
+ This text is shown in UIs related to an application name to help users and developers to
+ understand which sub-unit of an application is requesting permissions and using power.
+ [CHAR LIMIT=NONE]-->
+ <string name="offline_location_time_zone_detection_service_attribution">Time Zone Detector (No connectivity)</string>
<!-- Factory reset warning dialog strings--> <skip />
<!-- Shows up in the dialog's title to warn about an impeding factory reset. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 84556d41a07e..cd00fbf204cf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2166,6 +2166,7 @@
<java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
<java-symbol type="string" name="config_persistentDataPackageName" />
<java-symbol type="string" name="config_deviceConfiguratorPackageName" />
+ <java-symbol type="array" name="config_autoTimeSourcesPriority" />
<java-symbol type="bool" name="config_enableGeolocationTimeZoneDetection" />
<java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneOverlay" />
<java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
@@ -3002,7 +3003,6 @@
<java-symbol type="string" name="usb_mtp_launch_notification_description" />
<java-symbol type="color" name="notification_action_list" />
- <java-symbol type="color" name="notification_material_background_color" />
<!-- Resolver target actions -->
<java-symbol type="array" name="resolver_target_actions_pin" />
@@ -4113,4 +4113,6 @@
<java-symbol type="bool" name="config_trackerAppNeedsPermissions"/>
+ <!-- Component with platform query permissions for AppSearch -->
+ <java-symbol type="string" name="config_defaultAppSearchPlatformQuerierComponent" />
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 1afaf4f7f184..c0731c82bff3 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -215,8 +215,10 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
<item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="colorPopupBackground">?attr/colorBackgroundFloating</item>
+ <item name="panelColorBackground">?attr/colorBackgroundFloating</item>
</style>
<style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" />
@@ -943,8 +945,10 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
<item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="colorPopupBackground">?attr/colorBackgroundFloating</item>
+ <item name="panelColorBackground">?attr/colorBackgroundFloating</item>
</style>
<!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
@@ -1517,9 +1521,6 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
-
- <!-- volume background -->
- <item name="panelColorBackground">@color/primary_material_light</item>
</style>
<style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 5871e2e04687..7e992989426d 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -52,6 +52,7 @@ import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.SharedMemory;
import android.platform.test.annotations.Presubmit;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.DisplayCutout;
@@ -440,7 +441,8 @@ public class TransactionParcelTests {
IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1,
boolean b2, boolean b3, Configuration configuration,
CompatibilityInfo compatibilityInfo, Map map, Bundle bundle1, String s1,
- AutofillOptions ao, ContentCaptureOptions co, long[] disableCompatChanges)
+ AutofillOptions ao, ContentCaptureOptions co, long[] disableCompatChanges,
+ SharedMemory serializedSystemFontMap)
throws RemoteException {
}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbManagerTest.java b/core/tests/uwbtests/src/android/uwb/UwbManagerTest.java
new file mode 100644
index 000000000000..4983bed742fd
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/UwbManagerTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 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.uwb;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link UwbManager}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class UwbManagerTest {
+
+ public final Context mContext = InstrumentationRegistry.getContext();
+
+ @Test
+ public void testServiceAvailable() {
+ UwbManager manager = mContext.getSystemService(UwbManager.class);
+ if (UwbTestUtils.isUwbSupported(mContext)) {
+ assertNotNull(manager);
+ } else {
+ assertNull(manager);
+ }
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
index 62e0b629539b..fb7509248b38 100644
--- a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
+++ b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
@@ -16,6 +16,8 @@
package android.uwb;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.SystemClock;
import java.util.ArrayList;
@@ -24,6 +26,11 @@ import java.util.List;
public class UwbTestUtils {
private UwbTestUtils() {}
+ public static boolean isUwbSupported(Context context) {
+ PackageManager packageManager = context.getPackageManager();
+ return packageManager.hasSystemFeature(PackageManager.FEATURE_UWB);
+ }
+
public static AngleMeasurement getAngleMeasurement() {
return new AngleMeasurement.Builder()
.setRadians(getDoubleInRange(-Math.PI, Math.PI))
diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java
index 0061ea13f647..d59abb5916a0 100644
--- a/graphics/java/android/graphics/FrameInfo.java
+++ b/graphics/java/android/graphics/FrameInfo.java
@@ -43,7 +43,7 @@ public final class FrameInfo {
public long[] frameInfo = new long[FRAME_INFO_SIZE];
// Various flags set to provide extra metadata about the current frame
- private static final int FLAGS = 0;
+ public static final int FLAGS = 0;
// Is this the first-draw following a window layout?
public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1;
@@ -60,35 +60,35 @@ public final class FrameInfo {
@Retention(RetentionPolicy.SOURCE)
public @interface FrameInfoFlags {}
- private static final int FRAME_TIMELINE_VSYNC_ID = 1;
+ public static final int FRAME_TIMELINE_VSYNC_ID = 1;
// The intended vsync time, unadjusted by jitter
- private static final int INTENDED_VSYNC = 2;
+ public static final int INTENDED_VSYNC = 2;
// Jitter-adjusted vsync time, this is what was used as input into the
// animation & drawing system
- private static final int VSYNC = 3;
+ public static final int VSYNC = 3;
// The time of the oldest input event
- private static final int OLDEST_INPUT_EVENT = 4;
+ public static final int OLDEST_INPUT_EVENT = 4;
// The time of the newest input event
- private static final int NEWEST_INPUT_EVENT = 5;
+ public static final int NEWEST_INPUT_EVENT = 5;
// When input event handling started
- private static final int HANDLE_INPUT_START = 6;
+ public static final int HANDLE_INPUT_START = 6;
// When animation evaluations started
- private static final int ANIMATION_START = 7;
+ public static final int ANIMATION_START = 7;
// When ViewRootImpl#performTraversals() started
- private static final int PERFORM_TRAVERSALS_START = 8;
+ public static final int PERFORM_TRAVERSALS_START = 8;
// When View:draw() started
- private static final int DRAW_START = 9;
+ public static final int DRAW_START = 9;
// When the frame needs to be ready by
- private static final int FRAME_DEADLINE = 10;
+ public static final int FRAME_DEADLINE = 10;
// Must be the last one
private static final int FRAME_INFO_SIZE = FRAME_DEADLINE + 1;
@@ -99,23 +99,11 @@ public final class FrameInfo {
frameInfo[FRAME_TIMELINE_VSYNC_ID] = frameTimelineVsyncId;
frameInfo[INTENDED_VSYNC] = intendedVsync;
frameInfo[VSYNC] = usedVsync;
- frameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE;
- frameInfo[NEWEST_INPUT_EVENT] = 0;
frameInfo[FLAGS] = 0;
frameInfo[FRAME_DEADLINE] = frameDeadline;
}
/** checkstyle */
- public void updateInputEventTime(long inputEventTime, long inputEventOldestTime) {
- if (inputEventOldestTime < frameInfo[OLDEST_INPUT_EVENT]) {
- frameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime;
- }
- if (inputEventTime > frameInfo[NEWEST_INPUT_EVENT]) {
- frameInfo[NEWEST_INPUT_EVENT] = inputEventTime;
- }
- }
-
- /** checkstyle */
public void markInputHandlingStart() {
frameInfo[HANDLE_INPUT_START] = System.nanoTime();
}
@@ -131,13 +119,7 @@ public final class FrameInfo {
}
/** checkstyle */
- public void markDrawStart() {
- frameInfo[DRAW_START] = System.nanoTime();
- }
-
- /** checkstyle */
public void addFlags(@FrameInfoFlags long flags) {
frameInfo[FLAGS] |= flags;
}
-
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 36ef0a48fa20..24987daf87b5 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -81,6 +81,9 @@ public class Typeface {
private static String TAG = "Typeface";
+ /** @hide */
+ public static final boolean ENABLE_LAZY_TYPEFACE_INITIALIZATION = false;
+
private static final NativeAllocationRegistry sRegistry =
NativeAllocationRegistry.createMalloced(
Typeface.class.getClassLoader(), nativeGetReleaseFunc());
@@ -1329,7 +1332,9 @@ public class Typeface {
}
static {
- loadPreinstalledSystemFontMap();
+ if (!ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+ loadPreinstalledSystemFontMap();
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 39e32c694d2e..856c9c2484f3 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -125,9 +125,10 @@ android_library {
"protolog-lib",
"SettingsLib",
"WindowManager-Shell-proto",
+ "jsr330"
],
kotlincflags: ["-Xjvm-default=enable"],
manifest: "AndroidManifest.xml",
min_sdk_version: "26",
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
index 357f777e1270..176c620fa119 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
@@ -23,6 +23,8 @@ import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import javax.inject.Inject;
+
/**
* Utility class to calculate general fling animation when the finger is released.
*/
@@ -368,6 +370,7 @@ public class FlingAnimationUtils {
float mX2;
float mY2;
+ @Inject
public Builder(DisplayMetrics displayMetrics) {
mDisplayMetrics = displayMetrics;
reset();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
new file mode 100644
index 000000000000..8d9ad4d1b96c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip;
+
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.RemoteAction;
+import android.content.pm.ParceledListSlice;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+/**
+ * Interface to allow {@link com.android.wm.shell.pip.PipTaskOrganizer} to call into
+ * PiP menu when certain events happen (task appear/vanish, PiP move, etc.)
+ */
+public interface PipMenuController {
+
+ String MENU_WINDOW_TITLE = "PipMenuView";
+
+ /**
+ * Called when
+ * {@link PipTaskOrganizer#onTaskAppeared(RunningTaskInfo, SurfaceControl)}
+ * is called.
+ */
+ void attach(SurfaceControl leash);
+
+ /**
+ * Called when
+ * {@link PipTaskOrganizer#onTaskVanished(RunningTaskInfo)} is called.
+ */
+ void detach();
+
+ /**
+ * Check if menu is visible or not.
+ */
+ boolean isMenuVisible();
+
+ /**
+ * Show the PIP menu.
+ */
+ void showMenu();
+
+ /**
+ * Given a set of actions, update the menu.
+ */
+ void setAppActions(ParceledListSlice<RemoteAction> appActions);
+
+ /**
+ * Resize the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a
+ * need to synchronize the movements on the same frame as PiP.
+ */
+ default void resizePipMenu(@Nullable SurfaceControl pipLeash,
+ @Nullable SurfaceControl.Transaction t,
+ Rect destinationBounds) {}
+
+ /**
+ * Move the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a
+ * need to synchronize the movements on the same frame as PiP.
+ */
+ default void movePipMenu(@Nullable SurfaceControl pipLeash,
+ @Nullable SurfaceControl.Transaction t,
+ Rect destinationBounds) {}
+
+ /**
+ * Update the PiP menu with the given bounds for re-layout purposes.
+ */
+ default void updateMenuBounds(Rect destinationBounds) {}
+
+ /**
+ * Returns a default LayoutParams for the PIP Menu.
+ * @param width the PIP stack width.
+ * @param height the PIP stack height.
+ */
+ default WindowManager.LayoutParams getPipMenuLayoutParams(String title, int width, int height) {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
+ TYPE_APPLICATION_OVERLAY,
+ FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY | FLAG_NOT_TOUCHABLE,
+ PixelFormat.TRANSLUCENT);
+ lp.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
+ lp.setTitle(title);
+ return lp;
+ }
+}
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 7cc2a419354e..98ed822a387f 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
@@ -63,7 +63,6 @@ import com.android.internal.os.SomeArgs;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.pip.phone.PipMenuActivityController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipUpdateThread;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -135,8 +134,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private final Handler mUpdateHandler;
private final PipBoundsState mPipBoundsState;
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
- // TODO(b/172286265): Remove dependency on .pip.PHONE.PipMenuActivityController
- private final PipMenuActivityController mMenuActivityController;
+ private final @NonNull PipMenuController mPipMenuController;
private final PipAnimationController mPipAnimationController;
private final PipUiEventLogger mPipUiEventLoggerLogger;
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
@@ -264,7 +262,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
public PipTaskOrganizer(Context context, @NonNull PipBoundsState pipBoundsState,
@NonNull PipBoundsAlgorithm boundsHandler,
- PipMenuActivityController menuActivityController,
+ @NonNull PipMenuController pipMenuController,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional,
@NonNull DisplayController displayController,
@@ -274,7 +272,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mPipBoundsState = pipBoundsState;
mPipBoundsAlgorithm = boundsHandler;
- mMenuActivityController = menuActivityController;
+ mPipMenuController = pipMenuController;
mEnterExitAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
mSurfaceTransactionHelper = surfaceTransactionHelper;
@@ -501,9 +499,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mOnDisplayIdChangeCallback.accept(info.displayId);
}
- if (mMenuActivityController != null) {
- mMenuActivityController.onTaskAppeared();
- }
+ mPipMenuController.attach(leash);
+
if (mShouldIgnoreEnteringPipTransition) {
final Rect destinationBounds = mPipBoundsState.getBounds();
@@ -674,9 +671,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPictureInPictureParams = null;
mState = State.UNDEFINED;
mPipUiEventLoggerLogger.setTaskInfo(null);
- if (mMenuActivityController != null) {
- mMenuActivityController.onTaskVanished();
- }
+ mPipMenuController.detach();
}
@Override
@@ -956,9 +951,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mSurfaceTransactionHelper
.crop(tx, mLeash, destinationBounds)
.round(tx, mLeash, mState.isInPip());
- if (mMenuActivityController != null && mMenuActivityController.isMenuVisible()) {
+ if (mPipMenuController.isMenuVisible()) {
runOnMainHandler(() ->
- mMenuActivityController.resizePipMenu(mLeash, tx, destinationBounds));
+ mPipMenuController.resizePipMenu(mLeash, tx, destinationBounds));
} else {
tx.apply();
}
@@ -982,9 +977,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper.scale(tx, mLeash, startBounds, destinationBounds);
- if (mMenuActivityController != null && mMenuActivityController.isMenuVisible()) {
+ if (mPipMenuController.isMenuVisible()) {
runOnMainHandler(() ->
- mMenuActivityController.movePipMenu(mLeash, tx, destinationBounds));
+ mPipMenuController.movePipMenu(mLeash, tx, destinationBounds));
} else {
tx.apply();
}
@@ -1001,8 +996,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
removePipImmediately();
return;
- } else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA
- && mMenuActivityController != null) {
+ } else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
// TODO: Synchronize this correctly in #applyEnterPipSyncTransaction
finishResizeForMenu(destinationBounds);
return;
@@ -1015,13 +1009,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
private void finishResizeForMenu(Rect destinationBounds) {
- if (mMenuActivityController == null) {
- if (DEBUG) Log.d(TAG, "mMenuActivityController is null");
- return;
- }
runOnMainHandler(() -> {
- mMenuActivityController.movePipMenu(null, null, destinationBounds);
- mMenuActivityController.updateMenuBounds(destinationBounds);
+ mPipMenuController.movePipMenu(null, null, destinationBounds);
+ mPipMenuController.updateMenuBounds(destinationBounds);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index d4217553ef2d..5db8f3d7ef40 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -18,12 +18,6 @@ package com.android.wm.shell.pip.phone;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
import android.annotation.Nullable;
@@ -33,7 +27,6 @@ import android.app.RemoteAction;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.graphics.Matrix;
-import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Debug;
@@ -44,27 +37,26 @@ import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipMediaController.ActionListener;
+import com.android.wm.shell.pip.PipMenuController;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
/**
- * Manages the PiP menu activity which can show menu options or a scrim.
+ * Manages the PiP menu view which can show menu options or a scrim.
*
* The current media session provides actions whenever there are no valid actions provided by the
* current PiP activity. Otherwise, those actions always take precedence.
*/
-public class PipMenuActivityController {
+public class PhonePipMenuController implements PipMenuController {
private static final String TAG = "PipMenuActController";
- private static final String MENU_WINDOW_TITLE = "PipMenuView";
private static final boolean DEBUG = false;
public static final int MENU_STATE_NONE = 0;
@@ -124,7 +116,7 @@ public class PipMenuActivityController {
}
};
- public PipMenuActivityController(Context context,
+ public PhonePipMenuController(Context context,
PipMediaController mediaController, SystemWindows systemWindows) {
mContext = context;
mMediaController = mediaController;
@@ -138,20 +130,22 @@ public class PipMenuActivityController {
/**
* Attach the menu when the PiP task first appears.
*/
- public void onTaskAppeared() {
+ @Override
+ public void attach(SurfaceControl leash) {
attachPipMenuView();
}
/**
* Detach the menu when the PiP task is gone.
*/
- public void onTaskVanished() {
+ @Override
+ public void detach() {
hideMenu();
detachPipMenuView();
}
- public void onPinnedStackAnimationEnded() {
+ void onPinnedStackAnimationEnded() {
if (isMenuVisible()) {
mPipMenuView.onPipAnimationEnded();
}
@@ -163,7 +157,9 @@ public class PipMenuActivityController {
detachPipMenuView();
}
mPipMenuView = new PipMenuView(mContext, this);
- mSystemWindows.addView(mPipMenuView, getPipMenuLayoutParams(0, 0), 0, SHELL_ROOT_LAYER_PIP);
+ mSystemWindows.addView(mPipMenuView,
+ getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
+ 0, SHELL_ROOT_LAYER_PIP);
}
private void detachPipMenuView() {
@@ -181,9 +177,11 @@ public class PipMenuActivityController {
* Updates the layout parameters of the menu.
* @param destinationBounds New Menu bounds.
*/
+ @Override
public void updateMenuBounds(Rect destinationBounds) {
mSystemWindows.updateViewLayout(mPipMenuView,
- getPipMenuLayoutParams(destinationBounds.width(), destinationBounds.height()));
+ getPipMenuLayoutParams(MENU_WINDOW_TITLE, destinationBounds.width(),
+ destinationBounds.height()));
}
/**
@@ -206,6 +204,16 @@ public class PipMenuActivityController {
}
/**
+ * When other components requests the menu controller directly to show the menu, we must
+ * first fire off the request to the other listeners who will then propagate the call
+ * back to the controller with the right parameters.
+ */
+ @Override
+ public void showMenu() {
+ mListeners.forEach(Listener::onPipShowMenu);
+ }
+
+ /**
* Similar to {@link #showMenu(int, Rect, boolean, boolean, boolean)} but only show the menu
* upon PiP window transition is finished.
*/
@@ -250,6 +258,7 @@ public class PipMenuActivityController {
/**
* Move the PiP menu, which does a translation and possibly a scale transformation.
*/
+ @Override
public void movePipMenu(@Nullable SurfaceControl pipLeash,
@Nullable SurfaceControl.Transaction t,
Rect destinationBounds) {
@@ -290,6 +299,7 @@ public class PipMenuActivityController {
/**
* Does an immediate window crop of the PiP menu.
*/
+ @Override
public void resizePipMenu(@Nullable SurfaceControl pipLeash,
@Nullable SurfaceControl.Transaction t,
Rect destinationBounds) {
@@ -391,8 +401,9 @@ public class PipMenuActivityController {
}
/**
- * Sets the menu actions to the actions provided by the current PiP activity.
+ * Sets the menu actions to the actions provided by the current PiP menu.
*/
+ @Override
public void setAppActions(ParceledListSlice<RemoteAction> appActions) {
mAppActions = appActions;
updateMenuActions();
@@ -406,10 +417,6 @@ public class PipMenuActivityController {
mListeners.forEach(Listener::onPipDismiss);
}
- void onPipShowMenu() {
- mListeners.forEach(Listener::onPipShowMenu);
- }
-
/**
* @return the best set of actions to show in the PiP menu.
*/
@@ -421,21 +428,6 @@ public class PipMenuActivityController {
}
/**
- * Returns a default LayoutParams for the PIP Menu.
- * @param width the PIP stack width.
- * @param height the PIP stack height.
- */
- public static WindowManager.LayoutParams getPipMenuLayoutParams(int width, int height) {
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
- TYPE_APPLICATION_OVERLAY,
- FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY | FLAG_NOT_TOUCHABLE,
- PixelFormat.TRANSLUCENT);
- lp.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
- lp.setTitle(MENU_WINDOW_TITLE);
- return lp;
- }
-
- /**
* Updates the PiP menu with the best set of actions provided.
*/
private void updateMenuActions() {
@@ -521,7 +513,7 @@ public class PipMenuActivityController {
}
}
- public void dump(PrintWriter pw, String prefix) {
+ void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
pw.println(innerPrefix + "mMenuState=" + mMenuState);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 598b5d9b5d30..db02e284731e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -92,7 +92,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
private boolean mIsInFixedRotation;
private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
- protected PipMenuActivityController mMenuController;
+ protected PhonePipMenuController mMenuController;
protected PipTaskOrganizer mPipTaskOrganizer;
protected PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener =
new PipControllerPinnedStackListener();
@@ -229,7 +229,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
PipMediaController pipMediaController,
- PipMenuActivityController pipMenuActivityController,
+ PhonePipMenuController phonePipMenuController,
PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler,
WindowManagerShellWrapper windowManagerShellWrapper,
@@ -250,7 +250,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
mPipTaskOrganizer = pipTaskOrganizer;
mMainExecutor = mainExecutor;
mMediaController = pipMediaController;
- mMenuController = pipMenuActivityController;
+ mMenuController = phonePipMenuController;
mTouchHandler = pipTouchHandler;
mAppOpsListener = pipAppOpsListener;
mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
@@ -632,7 +632,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
public static PipController create(Context context, DisplayController displayController,
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
- PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
+ PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
@@ -641,7 +641,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm,
- pipBoundsState, pipMediaController, pipMenuActivityController, pipTaskOrganizer,
+ pipBoundsState, pipMediaController, phonePipMenuController, pipTaskOrganizer,
pipTouchHandler, windowManagerShellWrapper, taskStackListener, mainExecutor);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 6e3cd8e9aa09..4e991f2e919b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -23,9 +23,9 @@ import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTR
import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
-import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
-import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
-import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
+import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
+import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
+import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -105,7 +105,7 @@ public class PipMenuView extends FrameLayout {
private int mBetweenActionPaddingLand;
private AnimatorSet mMenuContainerAnimator;
- private PipMenuActivityController mController;
+ private PhonePipMenuController mController;
private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
new ValueAnimator.AnimatorUpdateListener() {
@@ -127,7 +127,7 @@ public class PipMenuView extends FrameLayout {
protected View mTopEndContainer;
protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
- public PipMenuView(Context context, PipMenuActivityController controller) {
+ public PipMenuView(Context context, PhonePipMenuController controller) {
super(context, null, 0);
mContext = context;
mController = controller;
@@ -182,7 +182,7 @@ public class PipMenuView extends FrameLayout {
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
if (action == ACTION_CLICK && mMenuState == MENU_STATE_CLOSE) {
- mController.onPipShowMenu();
+ mController.showMenu();
}
return super.performAccessibilityAction(host, action, args);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index 903f7d773896..e32d3b955081 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -70,7 +70,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
private final PipTaskOrganizer mPipTaskOrganizer;
private @NonNull PipBoundsState mPipBoundsState;
- private PipMenuActivityController mMenuController;
+ private PhonePipMenuController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
@@ -162,7 +162,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
};
public PipMotionHelper(Context context, @NonNull PipBoundsState pipBoundsState,
- PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
+ PipTaskOrganizer pipTaskOrganizer, PhonePipMenuController menuController,
PipSnapAlgorithm snapAlgorithm, FloatingContentCoordinator floatingContentCoordinator) {
mContext = context;
mPipTaskOrganizer = pipTaskOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index e5a49c430d82..bb545bdda922 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -103,7 +103,7 @@ public class PipResizeGestureHandler {
private InputMonitor mInputMonitor;
private InputEventReceiver mInputEventReceiver;
private PipTaskOrganizer mPipTaskOrganizer;
- private PipMenuActivityController mPipMenuActivityController;
+ private PhonePipMenuController mPhonePipMenuController;
private PipUiEventLogger mPipUiEventLogger;
private int mCtrlType;
@@ -112,7 +112,7 @@ public class PipResizeGestureHandler {
PipBoundsState pipBoundsState, PipMotionHelper motionHelper,
PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier,
Runnable updateMovementBoundsRunnable, PipUiEventLogger pipUiEventLogger,
- PipMenuActivityController menuActivityController) {
+ PhonePipMenuController menuActivityController) {
mContext = context;
mDisplayId = context.getDisplayId();
mMainExecutor = context.getMainExecutor();
@@ -122,7 +122,7 @@ public class PipResizeGestureHandler {
mPipTaskOrganizer = pipTaskOrganizer;
mMovementBoundsSupplier = movementBoundsSupplier;
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
- mPipMenuActivityController = menuActivityController;
+ mPhonePipMenuController = menuActivityController;
mPipUiEventLogger = pipUiEventLogger;
context.getDisplay().getRealSize(mMaxSize);
@@ -422,8 +422,8 @@ public class PipResizeGestureHandler {
mLastDownBounds.set(mPipBoundsState.getBounds());
}
if (!currentPipBounds.contains((int) ev.getX(), (int) ev.getY())
- && mPipMenuActivityController.isMenuVisible()) {
- mPipMenuActivityController.hideMenu();
+ && mPhonePipMenuController.isMenuVisible()) {
+ mPhonePipMenuController.hideMenu();
}
} else if (mAllowGesture) {
@@ -442,9 +442,9 @@ public class PipResizeGestureHandler {
mInputMonitor.pilferPointers();
}
if (mThresholdCrossed) {
- if (mPipMenuActivityController.isMenuVisible()) {
- mPipMenuActivityController.hideMenuWithoutResize();
- mPipMenuActivityController.hideMenu();
+ if (mPhonePipMenuController.isMenuVisible()) {
+ mPhonePipMenuController.hideMenuWithoutResize();
+ mPhonePipMenuController.hideMenu();
}
final Rect currentPipBounds = mPipBoundsState.getBounds();
mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(x, y,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index a78c4ecdb39f..99177016c30c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -18,9 +18,9 @@ package com.android.wm.shell.pip.phone;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_STASHING;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
-import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
-import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
-import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
+import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
+import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
+import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
@@ -78,7 +78,7 @@ public class PipTouchHandler {
private IPinnedStackController mPinnedStackController;
private WeakReference<Consumer<Rect>> mPipExclusionBoundsChangeListener;
- private final PipMenuActivityController mMenuController;
+ private final PhonePipMenuController mMenuController;
private final AccessibilityManager mAccessibilityManager;
private boolean mShowPipMenuOnAnimationEnd = false;
@@ -125,7 +125,7 @@ public class PipTouchHandler {
/**
* A listener for the PIP menu activity.
*/
- private class PipMenuListener implements PipMenuActivityController.Listener {
+ private class PipMenuListener implements PhonePipMenuController.Listener {
@Override
public void onPipMenuStateChanged(int menuState, boolean resize, Runnable callback) {
setMenuState(menuState, resize, callback);
@@ -152,7 +152,7 @@ public class PipTouchHandler {
@SuppressLint("InflateParams")
public PipTouchHandler(Context context,
- PipMenuActivityController menuController,
+ PhonePipMenuController menuController,
PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
PipTaskOrganizer pipTaskOrganizer,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
index 56e97b91c9d2..5d8d5e621846 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
@@ -36,7 +36,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
@@ -59,13 +58,14 @@ import com.android.wm.shell.pip.PipTaskOrganizer;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Manages the picture-in-picture (PIP) UI and states.
*/
public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
- private static final String TAG = "PipController";
- static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String TAG = "TvPipController";
+ static final boolean DEBUG = false;
/**
* Unknown or invalid state
@@ -111,15 +111,13 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
private final PipTaskOrganizer mPipTaskOrganizer;
private final PipMediaController mPipMediaController;
+ private final TvPipMenuController mTvPipMenuController;
private IActivityTaskManager mActivityTaskManager;
private int mState = STATE_NO_PIP;
private int mResumeResizePinnedStackRunnableState = STATE_NO_PIP;
private final Handler mHandler = new Handler();
private List<Listener> mListeners = new ArrayList<>();
- private Rect mPipBounds;
- private Rect mDefaultPipBounds = new Rect();
- private Rect mMenuModePipBounds;
private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
private int mPipTaskId = TASK_ID_NO_PIP;
private int mPinnedStackId = INVALID_STACK_ID;
@@ -187,11 +185,11 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
if (mImeVisible != imeVisible) {
if (imeVisible) {
// Save the IME height adjustment, and offset to not occlude the IME
- mPipBounds.offset(0, -imeHeight);
+ mPipBoundsState.getNormalBounds().offset(0, -imeHeight);
mImeHeightAdjustment = imeHeight;
} else {
// Apply the inverse adjustment when the IME is hidden
- mPipBounds.offset(0, mImeHeightAdjustment);
+ mPipBoundsState.getNormalBounds().offset(0, mImeHeightAdjustment);
}
mImeVisible = imeVisible;
resizePinnedStack(STATE_PIP);
@@ -206,10 +204,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
mTmpDisplayInfo.copyFrom(mPipBoundsState.getDisplayInfo());
mPipBoundsAlgorithm.getInsetBounds(mTmpInsetBounds);
- mPipBounds.set(mPipBoundsAlgorithm.getNormalBounds());
- if (mDefaultPipBounds.isEmpty()) {
- mDefaultPipBounds.set(mPipBoundsAlgorithm.getDefaultBounds());
- }
});
}
@@ -217,9 +211,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
mCustomActions = actions;
mHandler.post(() -> {
- for (int i = mListeners.size() - 1; i >= 0; --i) {
- mListeners.get(i).onPipMenuActionsChanged(mCustomActions);
- }
+ mTvPipMenuController.setAppActions(mCustomActions);
});
}
}
@@ -228,6 +220,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
PipBoundsState pipBoundsState,
PipBoundsAlgorithm pipBoundsAlgorithm,
PipTaskOrganizer pipTaskOrganizer,
+ TvPipMenuController tvPipMenuController,
PipMediaController pipMediaController,
PipNotification pipNotification,
TaskStackListenerImpl taskStackListener,
@@ -237,6 +230,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
mPipNotification = pipNotification;
mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipMediaController = pipMediaController;
+ mTvPipMenuController = tvPipMenuController;
+ mTvPipMenuController.attachPipController(this);
// Ensure that we have the display info in case we get calls to update the bounds
// before the listener calls back
final DisplayInfo displayInfo = new DisplayInfo();
@@ -289,9 +284,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
PipController.this.onActivityRestartAttempt(task, clearedTask);
}
});
-
- // TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
- PipMenuActivity.setPipController(this);
}
private void loadConfigurationsAndApply(Configuration newConfig) {
@@ -302,14 +294,10 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
return;
}
- Resources res = mContext.getResources();
- mMenuModePipBounds = Rect.unflattenFromString(res.getString(
- R.string.pip_menu_bounds));
+ final Rect menuBounds = Rect.unflattenFromString(
+ mContext.getResources().getString(R.string.pip_menu_bounds));
+ mPipBoundsState.setExpandedBounds(menuBounds);
- // Reset the PIP bounds and apply. PIP bounds can be changed by two reasons.
- // 1. Configuration changed due to the language change (RTL <-> RTL)
- // 2. SystemUI restarts after the crash
- mPipBounds = mDefaultPipBounds;
resizePinnedStack(getPinnedTaskInfo() == null ? STATE_NO_PIP : STATE_PIP);
}
@@ -379,16 +367,22 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
private void onActivityPinned(String packageName) {
- if (DEBUG) Log.d(TAG, "onActivityPinned()");
-
- RootTaskInfo taskInfo = getPinnedTaskInfo();
+ final RootTaskInfo taskInfo = getPinnedTaskInfo();
+ if (DEBUG) Log.d(TAG, "onActivityPinned, task=" + taskInfo);
if (taskInfo == null) {
Log.w(TAG, "Cannot find pinned stack");
return;
}
- if (DEBUG) Log.d(TAG, "PINNED_STACK:" + taskInfo);
+
+ // At this point PipBoundsState knows the correct aspect ratio for this pinned task, so we
+ // use PipBoundsAlgorithm to calculate the normal bounds for the task (PipBoundsAlgorithm
+ // will query PipBoundsState for the aspect ratio) and pass the bounds over to the
+ // PipBoundsState.
+ mPipBoundsState.setNormalBounds(mPipBoundsAlgorithm.getNormalBounds());
+
mPinnedStackId = taskInfo.taskId;
mPipTaskId = taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1];
+
// Set state to STATE_PIP so we show it when the pinned stack animation ends.
mState = STATE_PIP;
mPipMediaController.onActivityPinned();
@@ -434,8 +428,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
}
if (getState() == STATE_PIP) {
- if (mPipBounds != mDefaultPipBounds) {
- mPipBounds = mDefaultPipBounds;
+ if (!Objects.equals(mPipBoundsState.getBounds(), mPipBoundsState.getNormalBounds())) {
resizePinnedStack(STATE_PIP);
}
}
@@ -451,7 +444,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
Log.d(TAG,
"suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
}
-
mSuspendPipResizingReason |= reason;
}
@@ -478,6 +470,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
* @param state In Pip state also used to determine the new size for the Pip.
*/
public void resizePinnedStack(int state) {
+
if (DEBUG) {
Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state="
+ getStateDescription(), new Exception());
@@ -509,11 +502,11 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
break;
case STATE_PIP_MENU:
- newBounds = mMenuModePipBounds;
+ newBounds = mPipBoundsState.getExpandedBounds();
break;
case STATE_PIP: // fallthrough
default:
- newBounds = mPipBounds;
+ newBounds = mPipBoundsState.getNormalBounds();
break;
}
if (newBounds != null) {
@@ -544,10 +537,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onShowPipMenu();
}
- Intent intent = new Intent(mContext, PipMenuActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(PipMenuActivity.EXTRA_CUSTOM_ACTIONS, mCustomActions);
- mContext.startActivity(intent);
+
+ mTvPipMenuController.showMenu();
}
/**
@@ -650,8 +641,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
void onPipActivityClosed();
/** Invoked when the PIP menu gets shown. */
void onShowPipMenu();
- /** Invoked when the PIP menu actions change. */
- void onPipMenuActionsChanged(ParceledListSlice<RemoteAction> actions);
/** Invoked when the PIPed activity is about to return back to the fullscreen. */
void onMoveToFullscreen();
/** Invoked when we are above to start resizing the Pip. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java
index d2270c278161..689c3ede9efa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java
@@ -18,109 +18,110 @@ package com.android.wm.shell.pip.tv;
import android.animation.Animator;
import android.animation.AnimatorInflater;
-import android.app.Activity;
+import android.annotation.Nullable;
import android.app.RemoteAction;
-import android.content.Intent;
+import android.content.Context;
import android.content.pm.ParceledListSlice;
-import android.os.Bundle;
import android.util.Log;
+import android.view.KeyEvent;
+import android.view.SurfaceControl;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
+import android.widget.FrameLayout;
import com.android.wm.shell.R;
import java.util.Collections;
/**
- * Activity to show the PIP menu to control PIP.
- * TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
+ * The Menu View that shows controls of the PiP. Always fullscreen.
*/
-public class PipMenuActivity extends Activity implements PipController.Listener {
- private static final String TAG = "PipMenuActivity";
+public class PipMenuView extends FrameLayout implements PipController.Listener {
+ private static final String TAG = "PipMenuView";
private static final boolean DEBUG = PipController.DEBUG;
- static final String EXTRA_CUSTOM_ACTIONS = "custom_actions";
-
- private static PipController sPipController;
-
- private Animator mFadeInAnimation;
- private Animator mFadeOutAnimation;
+ private final PipController mPipController;
+ private final Animator mFadeInAnimation;
+ private final Animator mFadeOutAnimation;
+ private final PipControlsViewController mPipControlsViewController;
private boolean mRestorePipSizeWhenClose;
- private PipControlsViewController mPipControlsViewController;
- @Override
- protected void onCreate(Bundle bundle) {
- if (DEBUG) Log.d(TAG, "onCreate()");
+ public PipMenuView(Context context, PipController pipController) {
+ super(context, null, 0);
+ mPipController = pipController;
+
+ inflate(context, R.layout.tv_pip_menu, this);
- super.onCreate(bundle);
- if (sPipController == null) {
- finish();
- }
- setContentView(R.layout.tv_pip_menu);
mPipControlsViewController = new PipControlsViewController(
- findViewById(R.id.pip_controls), sPipController);
- sPipController.addListener(this);
+ findViewById(R.id.pip_controls), mPipController);
mRestorePipSizeWhenClose = true;
mFadeInAnimation = AnimatorInflater.loadAnimator(
- this, R.anim.tv_pip_menu_fade_in_animation);
+ mContext, R.anim.tv_pip_menu_fade_in_animation);
mFadeInAnimation.setTarget(mPipControlsViewController.getView());
mFadeOutAnimation = AnimatorInflater.loadAnimator(
- this, R.anim.tv_pip_menu_fade_out_animation);
+ mContext, R.anim.tv_pip_menu_fade_out_animation);
mFadeOutAnimation.setTarget(mPipControlsViewController.getView());
-
- onPipMenuActionsChanged(getIntent().getParcelableExtra(EXTRA_CUSTOM_ACTIONS));
}
@Override
- protected void onNewIntent(Intent intent) {
- if (DEBUG) Log.d(TAG, "onNewIntent(), intent=" + intent);
- super.onNewIntent(intent);
-
- onPipMenuActionsChanged(getIntent().getParcelableExtra(EXTRA_CUSTOM_ACTIONS));
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
+ && event.getAction() == KeyEvent.ACTION_UP) {
+ restorePipAndFinish();
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
}
- private void restorePipAndFinish() {
- if (DEBUG) Log.d(TAG, "restorePipAndFinish()");
-
- if (mRestorePipSizeWhenClose) {
- if (DEBUG) Log.d(TAG, " > restoring to the default position");
-
- // When PIP menu activity is closed, restore to the default position.
- sPipController.resizePinnedStack(PipController.STATE_PIP);
+ @Nullable
+ SurfaceControl getWindowSurfaceControl() {
+ final ViewRootImpl root = getViewRootImpl();
+ if (root == null) {
+ return null;
+ }
+ final SurfaceControl out = root.getSurfaceControl();
+ if (out != null && out.isValid()) {
+ return out;
}
- finish();
+ return null;
}
- @Override
- public void onResume() {
- if (DEBUG) Log.d(TAG, "onResume()");
-
- super.onResume();
+ void showMenu() {
+ mPipController.addListener(this);
mFadeInAnimation.start();
+ setAlpha(1.0f);
+ try {
+ WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
+ getViewRootImpl().getInputToken(), true /* grantFocus */);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to update focus as menu appears", e);
+ }
}
- @Override
- public void onPause() {
- if (DEBUG) Log.d(TAG, "onPause()");
-
- super.onPause();
+ void hideMenu() {
+ mPipController.removeListener(this);
+ mPipController.resumePipResizing(
+ PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
mFadeOutAnimation.start();
- restorePipAndFinish();
+ setAlpha(0.0f);
+ try {
+ WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
+ getViewRootImpl().getInputToken(), false /* grantFocus */);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to update focus as menu disappears", e);
+ }
}
- @Override
- protected void onDestroy() {
- if (DEBUG) Log.d(TAG, "onDestroy()");
-
- super.onDestroy();
- sPipController.removeListener(this);
- sPipController.resumePipResizing(
- PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
- }
+ private void restorePipAndFinish() {
+ if (DEBUG) Log.d(TAG, "restorePipAndFinish()");
- @Override
- public void onBackPressed() {
- if (DEBUG) Log.d(TAG, "onBackPressed()");
+ if (mRestorePipSizeWhenClose) {
+ if (DEBUG) Log.d(TAG, " > restoring to the default position");
- restorePipAndFinish();
+ // When PIP menu activity is closed, restore to the default position.
+ mPipController.resizePinnedStack(PipController.STATE_PIP);
+ }
+ hideMenu();
}
@Override
@@ -132,11 +133,10 @@ public class PipMenuActivity extends Activity implements PipController.Listener
public void onPipActivityClosed() {
if (DEBUG) Log.d(TAG, "onPipActivityClosed()");
- finish();
+ hideMenu();
}
- @Override
- public void onPipMenuActionsChanged(ParceledListSlice<RemoteAction> actions) {
+ void setAppActions(ParceledListSlice<RemoteAction> actions) {
if (DEBUG) Log.d(TAG, "onPipMenuActionsChanged()");
boolean hasCustomActions = actions != null && !actions.getList().isEmpty();
@@ -156,34 +156,15 @@ public class PipMenuActivity extends Activity implements PipController.Listener
// Moving PIP to fullscreen is implemented by resizing PINNED_STACK with null bounds.
// This conflicts with restoring PIP position, so disable it.
mRestorePipSizeWhenClose = false;
- finish();
+ hideMenu();
}
@Override
public void onPipResizeAboutToStart() {
if (DEBUG) Log.d(TAG, "onPipResizeAboutToStart()");
- finish();
- sPipController.suspendPipResizing(
+ hideMenu();
+ mPipController.suspendPipResizing(
PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
}
-
- @Override
- public void finish() {
- if (DEBUG) Log.d(TAG, "finish()", new RuntimeException());
-
- super.finish();
- }
-
- /**
- * TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
- *
- * @param pipController The singleton pipController instance for TV
- */
- public static void setPipController(PipController pipController) {
- if (sPipController != null) {
- return;
- }
- sPipController = pipController;
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
index b30dee4f331f..d56a88874420 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
@@ -19,12 +19,10 @@ package com.android.wm.shell.pip.tv;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.RemoteAction;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.media.MediaMetadata;
@@ -99,11 +97,6 @@ public class PipNotification implements PipController.Listener {
}
@Override
- public void onPipMenuActionsChanged(ParceledListSlice<RemoteAction> actions) {
- // no-op.
- }
-
- @Override
public void onMoveToFullscreen() {
dismissPipNotification();
mPackageName = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
new file mode 100644
index 000000000000..91aef670b946
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip.tv;
+
+import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
+
+import android.app.RemoteAction;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.view.SurfaceControl;
+
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipMenuController;
+
+/**
+ * Manages the visibility of the PiP Menu as user interacts with PiP.
+ */
+public class TvPipMenuController implements PipMenuController {
+
+ private final Context mContext;
+ private final SystemWindows mSystemWindows;
+ private final PipBoundsState mPipBoundsState;
+ private PipMenuView mMenuView;
+ private PipController mPipController;
+ private SurfaceControl mLeash;
+
+ public TvPipMenuController(Context context, PipBoundsState pipBoundsState,
+ SystemWindows systemWindows) {
+ mContext = context;
+ mPipBoundsState = pipBoundsState;
+ mSystemWindows = systemWindows;
+ }
+
+ void attachPipController(PipController pipController) {
+ mPipController = pipController;
+ }
+
+ @Override
+ public void showMenu() {
+ if (mMenuView != null) {
+ mSystemWindows.updateViewLayout(mMenuView, getPipMenuLayoutParams(MENU_WINDOW_TITLE,
+ mPipBoundsState.getDisplayBounds().width(),
+ mPipBoundsState.getDisplayBounds().height()));
+ mMenuView.showMenu();
+
+ // By default, SystemWindows views are above everything else.
+ // Set the relative z-order so the menu is below PiP.
+ if (mMenuView.getWindowSurfaceControl() != null && mLeash != null) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setRelativeLayer(mMenuView.getWindowSurfaceControl(), mLeash, -1);
+ t.apply();
+ }
+ }
+ }
+
+ @Override
+ public void attach(SurfaceControl leash) {
+ if (mMenuView == null) {
+ mMenuView = new PipMenuView(mContext, mPipController);
+ mSystemWindows.addView(mMenuView,
+ getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
+ 0, SHELL_ROOT_LAYER_PIP);
+ mLeash = leash;
+ }
+ }
+
+ @Override
+ public void detach() {
+ mSystemWindows.removeView(mMenuView);
+ mMenuView = null;
+ mLeash = null;
+ }
+
+ @Override
+ public void setAppActions(ParceledListSlice<RemoteAction> appActions) {
+ mMenuView.setAppActions(appActions);
+ }
+
+ @Override
+ public boolean isMenuVisible() {
+ return mMenuView != null && mMenuView.getAlpha() == 1.0f;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index 1e328a8dae40..c85561d96091 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -17,7 +17,7 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
@@ -54,7 +54,6 @@ import org.junit.runners.Parameterized
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 161435597)
class OpenAppToSplitScreenTest(
testName: String,
flickerSpec: Flicker
@@ -67,7 +66,8 @@ class OpenAppToSplitScreenTest(
val testApp = StandardAppHelper(instrumentation,
"com.android.wm.shell.flicker.testapp", "SimpleApp")
- return FlickerTestRunnerFactory(instrumentation)
+ // b/161435597 causes the test not to work on 90 degrees
+ return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
.buildTest { configuration ->
withTestName {
buildTestTag("appToSplitScreen", testApp, configuration)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt
new file mode 100644
index 000000000000..d2371bd766f5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen
+
+import androidx.test.filters.FlakyTest
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.repetitions
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test open app to split screen.
+ * To run this test: `atest WMShellFlickerTests:SplitScreenRotateOneLaunchedAppTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest
+class SplitScreenRotateOneLaunchedAppTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.wm.shell.flicker.testapp", "SimpleApp")
+
+ return FlickerTestRunnerFactory(instrumentation, repetitions = 3)
+ .buildTest { configuration ->
+ withTestName {
+ buildTestTag("splitScreenRotateOneApp", testApp, configuration)
+ }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ device.launchSplitScreen()
+ device.waitForIdle()
+ }
+ eachRun {
+ this.setRotation(configuration.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ }
+ }
+ transitions {
+ this.setRotation(configuration.endRotation)
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt
new file mode 100644
index 000000000000..67346424acd2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen
+
+import androidx.test.filters.FlakyTest
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.repetitions
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test open app to split screen.
+ * To run this test: `atest WMShellFlickerTests:SplitScreenRotateTwoLaunchedAppTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest
+class SplitScreenRotateTwoLaunchedAppTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.wm.shell.flicker.testapp", "SimpleApp")
+ val secondaryApp = StandardAppHelper(instrumentation,
+ "com.android.wm.shell.flicker.testapp",
+ "SplitScreenSecondaryApp")
+
+ return FlickerTestRunnerFactory(instrumentation, repetitions = 3)
+ .buildTest { configuration ->
+ withTestName {
+ buildTestTag("splitScreenRotateTwoApps", testApp, configuration)
+ }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ device.pressHome()
+ secondaryApp.open()
+ device.pressHome()
+ device.launchSplitScreen()
+ device.reopenAppFromOverview()
+ device.waitForIdle()
+ }
+ eachRun {
+ this.setRotation(configuration.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ secondaryApp.exit()
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ }
+ }
+ transitions {
+ this.setRotation(configuration.endRotation)
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 8d3774cee1e0..45e4241d5bc6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -44,7 +44,7 @@ import android.window.WindowContainerToken;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.pip.phone.PipMenuActivityController;
+import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
@@ -66,7 +66,7 @@ public class PipTaskOrganizerTest extends ShellTestCase {
@Mock private DisplayController mMockdDisplayController;
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
- @Mock private PipMenuActivityController mMenuActivityController;
+ @Mock private PhonePipMenuController mMockPhonePipMenuController;
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
@Mock private PipUiEventLogger mMockPipUiEventLogger;
@Mock private Optional<SplitScreen> mMockOptionalSplitScreen;
@@ -83,9 +83,9 @@ public class PipTaskOrganizerTest extends ShellTestCase {
mComponent2 = new ComponentName(mContext, "component2");
mPipBoundsState = new PipBoundsState(mContext);
mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mPipBoundsState,
- mMockPipBoundsAlgorithm, mMenuActivityController, mMockPipSurfaceTransactionHelper,
- mMockOptionalSplitScreen, mMockdDisplayController, mMockPipUiEventLogger,
- mMockShellTaskOrganizer));
+ mMockPipBoundsAlgorithm, mMockPhonePipMenuController,
+ mMockPipSurfaceTransactionHelper, mMockOptionalSplitScreen, mMockdDisplayController,
+ mMockPipUiEventLogger, mMockShellTaskOrganizer));
preparePipTaskOrg();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 88c8eb902a6f..4687d2d9667c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -61,7 +61,7 @@ public class PipControllerTest extends ShellTestCase {
private PipController mPipController;
@Mock private DisplayController mMockDisplayController;
- @Mock private PipMenuActivityController mMockPipMenuActivityController;
+ @Mock private PhonePipMenuController mMockPhonePipMenuController;
@Mock private PipAppOpsListener mMockPipAppOpsListener;
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
@Mock private PipMediaController mMockPipMediaController;
@@ -77,7 +77,7 @@ public class PipControllerTest extends ShellTestCase {
MockitoAnnotations.initMocks(this);
mPipController = new PipController(mContext, mMockDisplayController,
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipBoundsState,
- mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
+ mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer,
mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
mMockExecutor);
doAnswer(invocation -> {
@@ -110,7 +110,7 @@ public class PipControllerTest extends ShellTestCase {
assertNull(PipController.create(spyContext, mMockDisplayController,
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipBoundsState,
- mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
+ mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer,
mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
mMockExecutor));
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index abbc681f53fe..e60221943898 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -60,7 +60,7 @@ public class PipTouchHandlerTest extends ShellTestCase {
private PipTouchHandler mPipTouchHandler;
@Mock
- private PipMenuActivityController mPipMenuActivityController;
+ private PhonePipMenuController mPhonePipMenuController;
@Mock
private PipTaskOrganizer mPipTaskOrganizer;
@@ -92,7 +92,7 @@ public class PipTouchHandlerTest extends ShellTestCase {
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState);
mPipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
mPipSnapAlgorithm = new PipSnapAlgorithm();
- mPipTouchHandler = new PipTouchHandler(mContext, mPipMenuActivityController,
+ mPipTouchHandler = new PipTouchHandler(mContext, mPhonePipMenuController,
mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer,
mFloatingContentCoordinator, mPipUiEventLogger);
mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index fd18d2f9192d..8b20492543f7 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -20,7 +20,7 @@
namespace android {
namespace uirenderer {
-const std::string FrameInfoNames[] = {
+const std::array<std::string, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames = {
"Flags",
"FrameTimelineVsyncId",
"IntendedVsync",
@@ -42,10 +42,6 @@ const std::string FrameInfoNames[] = {
"GpuCompleted",
};
-static_assert((sizeof(FrameInfoNames) / sizeof(FrameInfoNames[0])) ==
- static_cast<int>(FrameInfoIndex::NumIndexes),
- "size mismatch: FrameInfoNames doesn't match the enum!");
-
static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 19,
"Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index bb875e35f6f7..738246d56d0d 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -21,6 +21,7 @@
#include <cutils/compiler.h>
#include <utils/Timers.h>
+#include <array>
#include <memory.h>
#include <string>
@@ -60,7 +61,7 @@ enum class FrameInfoIndex {
NumIndexes
};
-extern const std::string FrameInfoNames[];
+extern const std::array<std::string, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames;
namespace FrameInfoFlags {
enum {
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index a9da77230214..c2613716cd07 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -308,6 +308,7 @@ public class Tuner implements AutoCloseable {
.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__UNKNOWN);
}
+ releaseAll();
mHandler.sendMessage(mHandler.obtainMessage(MSG_RESOURCE_LOST));
}
};
@@ -610,7 +611,6 @@ public class Tuner implements AutoCloseable {
break;
}
case MSG_RESOURCE_LOST: {
- releaseAll();
if (mOnResourceLostListener != null
&& mOnResourceLostListenerExecutor != null) {
mOnResourceLostListenerExecutor.execute(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index b061df1423ba..40b0fcff3aac 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -496,11 +496,14 @@ final class SettingsState {
public List<String> setSettingsLocked(String prefix, Map<String, String> keyValues,
String packageName) {
List<String> changedKeys = new ArrayList<>();
+ final Iterator<Map.Entry<String, Setting>> iterator = mSettings.entrySet().iterator();
// Delete old keys with the prefix that are not part of the new set.
- for (int i = 0; i < mSettings.keySet().size(); ++i) {
- String key = mSettings.keyAt(i);
- if (key.startsWith(prefix) && !keyValues.containsKey(key)) {
- Setting oldState = mSettings.remove(key);
+ while (iterator.hasNext()) {
+ Map.Entry<String, Setting> entry = iterator.next();
+ final String key = entry.getKey();
+ final Setting oldState = entry.getValue();
+ if (key != null && key.startsWith(prefix) && !keyValues.containsKey(key)) {
+ iterator.remove();
FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, key,
/* value= */ "", /* newValue= */ "", oldState.value, /* tag */ "", false,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 48c0dc4fb2b8..75eea8db8085 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -230,7 +230,7 @@ public class SettingsBackupTest {
Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR,
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV,
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR,
- Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS,
+ Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH,
Settings.Global.DEVICE_DEMO_MODE,
Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS,
Settings.Global.BATTERY_SAVER_CONSTANTS,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 2e3ea24f62e2..92b1ca731a30 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -332,6 +332,9 @@
<!-- Permission needed for CTS test - DisplayTest -->
<uses-permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS" />
+ <!-- Permission needed for CTS test - MatchContentFrameRateTest -->
+ <uses-permission android:name="android.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE" />
+
<!-- Permission needed for CTS test - TimeManagerTest -->
<uses-permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 52b41a43c63e..2da958f6b8b9 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -516,20 +516,6 @@
android:excludeFromRecents="true"
android:visibleToInstantApps="true"/>
- <!-- started from PipController -->
- <activity
- android:name="com.android.wm.shell.pip.tv.PipMenuActivity"
- android:permission="com.android.systemui.permission.SELF"
- android:exported="false"
- android:theme="@style/PipTheme"
- android:launchMode="singleTop"
- android:taskAffinity=""
- android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|locale|layoutDirection"
- android:resizeableActivity="true"
- android:supportsPictureInPicture="true"
- androidprv:alwaysFocusable="true"
- android:excludeFromRecents="true" />
-
<!-- started from TvNotificationPanel -->
<activity
android:name=".statusbar.tv.notifications.TvNotificationPanelActivity"
diff --git a/packages/SystemUI/res/color/background_protect_secondary.xml b/packages/SystemUI/res-keyguard/color/notification_background_dimmed_color.xml
index 97744dbe9190..3345e6e42500 100644
--- a/packages/SystemUI/res/color/background_protect_secondary.xml
+++ b/packages/SystemUI/res-keyguard/color/notification_background_dimmed_color.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2017 The Android Open Source Project
+ ~ 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.
@@ -14,7 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="?attr/wallpaperTextColorSecondary" />
+ <item android:alpha="0.7" android:color="?android:attr/colorBackground" />
</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
index cc2089f69287..99c70a54a3cd 100644
--- a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
+++ b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
@@ -19,13 +19,13 @@
<item android:id="@android:id/background">
<shape
android:color="@android:color/transparent">
- <stroke android:width="1dp" android:color="?attr/wallpaperTextColorSecondary"/>
+ <stroke android:width="1dp" android:color="?android:attr/textColorSecondary"/>
<corners android:radius="24dp"/>
</shape>
</item>
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
- <solid android:color="?attr/wallpaperTextColorSecondary"/>
+ <solid android:color="?android:attr/textColorSecondary"/>
<corners android:radius="24dp"/>
</shape>
</item>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
index b06d6a989cb8..e1550aa0c87c 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -34,7 +34,7 @@
android:layout_weight="7"
/>
- <!-- Password entry field -->
+ <!-- Password entry field -->
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="280dp"
@@ -51,9 +51,9 @@
android:textStyle="normal"
android:inputType="textPassword"
android:textSize="16sp"
- android:textColor="?attr/wallpaperTextColor"
android:textAppearance="?android:attr/textAppearanceMedium"
android:imeOptions="flagForceAscii|actionDone"
+ android:textCursorDrawable="@null"
android:maxLength="500"
/>
@@ -65,7 +65,7 @@
android:contentDescription="@string/accessibility_ime_switch_button"
android:clickable="true"
android:padding="8dip"
- android:tint="@color/background_protected"
+ android:tint="?android:attr/textColorPrimary"
android:layout_gravity="end|center_vertical"
android:background="?android:attr/selectableItemBackground"
android:visibility="gone"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index a75b35d117b6..87c98d2e9597 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -46,11 +46,10 @@
android:id="@+id/pinEntry"
android:layout_width="@dimen/keyguard_security_width"
android:layout_height="match_parent"
- android:gravity="center"
+ style="@style/Widget.TextView.Password"
android:layout_centerHorizontal="true"
android:layout_marginRight="72dp"
androidprv:scaledTextSize="@integer/scaled_password_text_size"
- android:textColor="?attr/wallpaperTextColor"
android:contentDescription="@string/keyguard_accessibility_pin_area"
/>
<View
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index cd61a3775bf7..912d7bbf7ef5 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -64,7 +64,6 @@
android:layout_centerHorizontal="true"
android:layout_marginRight="72dp"
androidprv:scaledTextSize="@integer/scaled_password_text_size"
- android:textColor="?attr/wallpaperTextColor"
android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
/>
<View
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index bb757356f2b9..81b49648ab62 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -65,7 +65,6 @@
android:layout_centerHorizontal="true"
android:layout_marginRight="72dp"
androidprv:scaledTextSize="@integer/scaled_password_text_size"
- android:textColor="?attr/wallpaperTextColor"
android:contentDescription="@string/keyguard_accessibility_sim_puk_area"
/>
<View
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 401f3e3e0685..bc48e8fe3eea 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -20,41 +20,46 @@
<resources>
<!-- Keyguard PIN pad styles -->
<style name="Keyguard.TextView" parent="@android:style/Widget.DeviceDefault.TextView">
- <item name="android:textColor">?attr/wallpaperTextColorSecondary</item>
<item name="android:textSize">@dimen/kg_status_line_font_size</item>
</style>
<style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI">
- <item name="android:textColor">?attr/wallpaperTextColorSecondary</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">14dp</item>
<item name="android:background">@drawable/kg_emergency_button_background</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:paddingLeft">12dp</item>
<item name="android:paddingRight">12dp</item>
</style>
- <style name="Widget.TextView.NumPadKey" parent="@android:style/Widget.TextView">
+ <style name="Widget.TextView.NumPadKey" parent="@android:style/Widget.DeviceDefault.TextView">
<item name="android:singleLine">true</item>
<item name="android:gravity">center_horizontal|center_vertical</item>
<item name="android:background">@null</item>
<item name="android:textSize">32sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">?attr/wallpaperTextColor</item>
<item name="android:paddingBottom">-16dp</item>
+ <item name="android:colorControlHighlight">?android:attr/textColorPrimary</item>
+ </style>
+ <style name="Widget.TextView.Password" parent="@android:style/Widget.TextView">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:gravity">center</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
- <style name="Keyguard.ImageButton.NumPadDelete" parent="@android:style/Widget.ImageButton">
+ <style name="Keyguard.ImageButton.NumPadDelete" parent="@android:style/Widget.DeviceDefault.ImageButton">
<item name="android:src">@drawable/ic_backspace_black_24dp</item>
<item name="android:paddingBottom">11sp</item>
- <item name="android:tint">@color/pin_delete_color</item>
+ <item name="android:tint">?android:attr/textColorSecondary</item>
<item name="android:tintMode">src_in</item>
<item name="android:src">@drawable/ic_backspace_black_24dp</item>
</style>
- <style name="Keyguard.ImageButton.NumPadEnter" parent="@android:style/Widget.ImageButton">
+ <style name="Keyguard.ImageButton.NumPadEnter" parent="@android:style/Widget.DeviceDefault.ImageButton">
<item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
<item name="android:paddingBottom">11sp</item>
</style>
- <style name="Widget.TextView.NumPadKey.Klondike" parent="Widget.TextView.NumPadKey">
+ <style name="Widget.TextView.NumPadKey.Klondike">
<item name="android:textSize">12sp</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
- <item name="android:textColor">?attr/wallpaperTextColorSecondary</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:paddingBottom">0dp</item>
</style>
@@ -95,15 +100,9 @@
</style>
<style name="PasswordTheme" parent="Theme.SystemUI">
- <item name="android:textColor">?attr/wallpaperTextColor</item>
- <item name="android:colorControlNormal">?attr/wallpaperTextColor</item>
- <item name="android:colorControlActivated">?attr/wallpaperTextColor</item>
- </style>
-
- <style name="PasswordTheme.Light" parent="Theme.SystemUI.Light">
- <item name="android:textColor">?attr/wallpaperTextColor</item>
- <item name="android:colorControlNormal">?attr/wallpaperTextColor</item>
- <item name="android:colorControlActivated">?attr/wallpaperTextColor</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:colorControlNormal">?android:attr/textColorPrimary</item>
+ <item name="android:colorControlActivated">?android:attr/textColorPrimary</item>
</style>
<style name="Theme.SystemUI.KeyguardPresentation">
diff --git a/packages/SystemUI/res/color/pin_delete_color.xml b/packages/SystemUI/res/color/pin_delete_color.xml
index 7d4f1321d52f..c1b4cf87e923 100644
--- a/packages/SystemUI/res/color/pin_delete_color.xml
+++ b/packages/SystemUI/res/color/pin_delete_color.xml
@@ -15,5 +15,5 @@
~ limitations under the License
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.61" android:color="?attr/wallpaperTextColor" />
+ <item android:alpha="0.61" android:color="?android:attr/textColor" />
</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/pin_divider_color.xml b/packages/SystemUI/res/color/pin_divider_color.xml
index aff23171eee3..e05772fab8b2 100644
--- a/packages/SystemUI/res/color/pin_divider_color.xml
+++ b/packages/SystemUI/res/color/pin_divider_color.xml
@@ -15,5 +15,5 @@
~ limitations under the License
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.45" android:color="?attr/wallpaperTextColorSecondary" />
+ <item android:alpha="0.45" android:color="?android:attr/textColorSecondary" />
</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/qs_background_dark.xml b/packages/SystemUI/res/color/qs_background_dark.xml
index 24afebde046b..c47959a04fff 100644
--- a/packages/SystemUI/res/color/qs_background_dark.xml
+++ b/packages/SystemUI/res/color/qs_background_dark.xml
@@ -16,5 +16,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="1"
- android:color="?android:attr/colorBackgroundFloating"/>
+ android:color="?android:attr/colorBackground"/>
</selector>
diff --git a/packages/SystemUI/res/drawable/notification_guts_bg.xml b/packages/SystemUI/res/drawable/notification_guts_bg.xml
index 2fe6c7b2d1a2..d62687883c35 100644
--- a/packages/SystemUI/res/drawable/notification_guts_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_guts_bg.xml
@@ -16,7 +16,7 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/notification_material_background_color" />
+ <solid android:color="?android:attr/colorBackground" />
<!--The radius is 1dp smaller than the notification one, to avoid aliasing bugs on the corners -->
<corners android:radius="1dp" />
</shape>
diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml
index ae456631c4f1..1e9be2fb9b05 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg.xml
@@ -19,7 +19,7 @@
android:color="@color/notification_ripple_untinted_color">
<item>
<shape>
- <solid android:color="@color/notification_material_background_color" />
+ <solid android:color="?android:attr/colorBackground" />
</shape>
</item>
</ripple> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notification_material_bg_dim.xml b/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
index b6a8b70bb3e0..1127d3c247fd 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
@@ -17,7 +17,7 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
- <solid android:color="@color/notification_material_background_dimmed_color" />
+ <solid android:color="@color/notification_background_dimmed_color" />
</shape>
</item>
</ripple>
diff --git a/packages/SystemUI/res/drawable/qs_navbar_scrim.xml b/packages/SystemUI/res/drawable/qs_navbar_scrim.xml
deleted file mode 100644
index bbb2617db4a0..000000000000
--- a/packages/SystemUI/res/drawable/qs_navbar_scrim.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <gradient
- android:type="linear"
- android:angle="90"
- android:startColor="#55000000"
- android:endColor="#00000000" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/app_ops_info.xml b/packages/SystemUI/res/layout/app_ops_info.xml
index 667c857b6967..ecf572ba4a5c 100644
--- a/packages/SystemUI/res/layout/app_ops_info.xml
+++ b/packages/SystemUI/res/layout/app_ops_info.xml
@@ -26,7 +26,7 @@
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
- android:background="@color/notification_material_background_color"
+ android:background="?android:attr/colorBackground"
android:theme="@*android:style/Theme.DeviceDefault.Light">
<!-- Package Info -->
diff --git a/packages/SystemUI/res/layout/feedback_info.xml b/packages/SystemUI/res/layout/feedback_info.xml
index 5e847a28558e..7047c1b21961 100644
--- a/packages/SystemUI/res/layout/feedback_info.xml
+++ b/packages/SystemUI/res/layout/feedback_info.xml
@@ -26,7 +26,7 @@
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
- android:background="@color/notification_material_background_color"
+ android:background="?android:attr/colorBackground"
android:theme="@*android:style/Theme.DeviceDefault.Light">
<!-- Package Info -->
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 10ad8291636e..fcc1aed65470 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -24,7 +24,7 @@
android:clipChildren="true"
android:clipToPadding="true"
android:orientation="vertical"
- android:background="@color/notification_material_background_color"
+ android:background="?android:attr/colorBackground"
android:paddingStart="12dp">
<!-- Package Info -->
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 5399f57c322f..fb75dd348a41 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -22,5 +22,4 @@
android:focusable="true"
android:id="@+id/notification_guts"
android:visibility="gone"
- android:gravity="top|start"
- android:theme="@*android:style/Theme.DeviceDefault.Light"/>
+ android:gravity="top|start"/>
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
index 253bc328c5b8..dc9d92001351 100644
--- a/packages/SystemUI/res/layout/notification_snooze.xml
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -20,7 +20,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:background="@color/notification_material_background_color"
+ android:background="?android:attr/colorBackground"
android:theme="@style/Theme.SystemUI">
<RelativeLayout
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 1d4b98242519..75f76b431da8 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -92,13 +92,5 @@
layout="@layout/keyguard_bottom_area"
android:visibility="gone" />
- <com.android.systemui.statusbar.AlphaOptimizedView
- android:id="@+id/qs_navbar_scrim"
- android:layout_height="96dp"
- android:layout_width="match_parent"
- android:layout_gravity="bottom"
- android:visibility="invisible"
- android:background="@drawable/qs_navbar_scrim" />
-
<include layout="@layout/status_bar_expanded_plugin_frame"/>
</com.android.systemui.statusbar.phone.NotificationPanelView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index b5822c889f1c..e33f186dcbb7 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -58,7 +58,6 @@
android:src="@drawable/status_bar_notification_section_header_clear_btn"
android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
android:scaleType="center"
- android:tint="?attr/wallpaperTextColor"
android:tintMode="src_in"
android:visibility="gone"
android:forceHasOverlappingRendering="false"
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index cb9e178de243..8cc747bf04d6 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -17,22 +17,13 @@
NOTE: You might also want to edit: core/res/res/values-night/*.xml
-->
<resources>
- <!-- The color of the material notification background -->
- <color name="notification_material_background_color">@*android:color/notification_material_background_color</color>
-
<!-- The color of the legacy notifications with customs backgrounds (gingerbread and lollipop.)
It's fine to override this color since at that point the shade was dark. -->
- <color name="notification_legacy_background_color">@*android:color/notification_material_background_color</color>
-
- <!-- The color of the material notification background when dimmed -->
- <color name="notification_material_background_dimmed_color">#aa000000</color>
+ <color name="notification_legacy_background_color">@color/GM2_grey_900</color>
<!-- The color of the dividing line between grouped notifications while . -->
<color name="notification_divider_color">#212121</color>
- <!-- The background color of the notification shade -->
- <color name="notification_shade_background_color">@color/GM2_grey_900</color>
-
<!-- The color of the gear shown behind a notification -->
<color name="notification_gear_color">@color/GM2_grey_500</color>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index be36316d013c..c51e0bf2c31b 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -80,21 +80,12 @@
<!-- The color of the legacy notification background -->
<color name="notification_legacy_background_color">#ff1a1a1a</color>
- <!-- The color of the material notification background -->
- <color name="notification_material_background_color">@*android:color/notification_material_background_color</color>
-
- <!-- The color of the material notification background when dimmed -->
- <color name="notification_material_background_dimmed_color">#ccffffff</color>
-
<!-- The color of the material notification background when dark -->
<color name="notification_material_background_dark_color">#ff333333</color>
<!-- The color of the dividing line between grouped notifications. -->
<color name="notification_divider_color">#FF616161</color>
- <!-- The background color of the notification shade -->
- <color name="notification_shade_background_color">@color/GM2_grey_200</color>
-
<!-- The color of the ripples on the untinted notifications -->
<color name="notification_ripple_untinted_color">#28000000</color>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index f38e653190b0..0697c5c0084c 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -334,7 +334,6 @@
<item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item>
<item name="android:colorError">@*android:color/error_color_material_light</item>
<item name="android:colorControlHighlight">#40000000</item>
- <item name="passwordStyle">@style/PasswordTheme.Light</item>
<item name="shadowRadius">0</item>
<!-- Needed for MediaRoute chooser dialog -->
@@ -356,8 +355,8 @@
</style>
<style name="LockPatternStyle">
- <item name="*android:regularColor">?attr/wallpaperTextColor</item>
- <item name="*android:successColor">?attr/wallpaperTextColor</item>
+ <item name="*android:regularColor">?android:attr/textColorPrimary</item>
+ <item name="*android:successColor">?android:attr/textColorPrimary</item>
<item name="*android:errorColor">?android:attr/colorError</item>
</style>
@@ -555,8 +554,8 @@
<style
name="TextAppearance.NotificationSectionHeaderButton"
- parent="@android:style/Widget.Material.Button.Borderless">
- <item name="android:textColor">?attr/wallpaperTextColor</item>
+ parent="@android:style/Widget.DeviceDefault.Button.Borderless">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">14sp</item>
<item name="android:minWidth">0dp</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 487e0d8ea38e..b7d7498e8960 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -41,6 +41,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.EmergencyAffordanceManager;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.util.EmergencyDialerConstants;
@@ -148,6 +149,17 @@ public class EmergencyButton extends Button {
return super.onTouchEvent(event);
}
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ int color = Utils.getColorAttrDefaultColor(getContext(),
+ android.R.attr.textColorSecondary);
+ setTextColor(color);
+ setBackground(getContext()
+ .getDrawable(com.android.systemui.R.drawable.kg_emergency_button_background));
+ }
+
@Override
public boolean performLongClick() {
return super.performLongClick();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 217cf701b265..5760565aaab1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
import static com.android.keyguard.KeyguardAbsKeyInputView.MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT;
+import android.annotation.CallSuper;
import android.content.res.ColorStateList;
import android.os.AsyncTask;
import android.os.CountDownTimer;
@@ -87,6 +88,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
@Override
protected void onViewAttached() {
+ super.onViewAttached();
mView.setKeyDownListener(mKeyDownListener);
mView.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
@@ -110,6 +112,13 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
}
}
+ @CallSuper
+ @Override
+ public void reloadColors() {
+ super.reloadColors();
+ mMessageAreaController.reloadColors();
+ }
+
@Override
public boolean needsInput() {
return false;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index fbda818740e8..6aa5e0df3653 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import android.annotation.CallSuper;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.telephony.TelephonyManager;
@@ -24,6 +25,7 @@ import android.view.inputmethod.InputMethodManager;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -37,6 +39,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
private final SecurityMode mSecurityMode;
private final KeyguardSecurityCallback mKeyguardSecurityCallback;
+ private final EmergencyButton mEmergencyButton;
private boolean mPaused;
@@ -68,6 +71,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
super(view);
mSecurityMode = securityMode;
mKeyguardSecurityCallback = keyguardSecurityCallback;
+ mEmergencyButton = view == null ? null : view.findViewById(R.id.emergency_call_button);
}
@Override
@@ -112,6 +116,16 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
public void showMessage(CharSequence message, ColorStateList colorState) {
}
+ /**
+ * Reload colors from resources.
+ **/
+ @CallSuper
+ public void reloadColors() {
+ if (mEmergencyButton != null) {
+ mEmergencyButton.reloadColors();
+ }
+ }
+
public void startAppearAnimation() {
mView.startAppearAnimation();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 1a0a4370fca4..561ea4075291 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -29,6 +29,7 @@ import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import java.lang.ref.WeakReference;
@@ -69,7 +70,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
void onThemeChanged() {
TypedArray array = mContext.obtainStyledAttributes(new int[] {
- R.attr.wallpaperTextColor
+ android.R.attr.textColor
});
ColorStateList newTextColors = ColorStateList.valueOf(array.getColor(0, Color.RED));
array.recycle();
@@ -77,6 +78,11 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
update();
}
+ void reloadColor() {
+ mDefaultColorState = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary);
+ update();
+ }
+
void onDensityOrFontScaleChanged() {
TypedArray array = mContext.obtainStyledAttributes(R.style.Keyguard_TextView, new int[] {
android.R.attr.textSize
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 1618e8e58055..6e40f025da50 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -93,6 +93,13 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag
mView.setNextMessageColor(colorState);
}
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ mView.reloadColor();
+ }
+
/** Factory for creating {@link com.android.keyguard.KeyguardMessageAreaController}. */
public static class Factory {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index d34ea8c5e018..5e339172ca28 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.os.UserHandle;
import android.text.Editable;
@@ -30,12 +31,14 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
-import android.widget.TextView;
+import android.widget.EditText;
+import android.widget.ImageView;
import android.widget.TextView.OnEditorActionListener;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -51,8 +54,8 @@ public class KeyguardPasswordViewController
private final InputMethodManager mInputMethodManager;
private final DelayableExecutor mMainExecutor;
private final boolean mShowImeAtScreenOn;
- private TextView mPasswordEntry;
- private View mSwitchImeButton;
+ private EditText mPasswordEntry;
+ private ImageView mSwitchImeButton;
private final OnEditorActionListener mOnEditorActionListener = (v, actionId, event) -> {
// Check if this was the result of hitting the enter key
@@ -88,6 +91,18 @@ public class KeyguardPasswordViewController
}
};
+ @Override
+ public void reloadColors() {
+ super.reloadColors();
+ int textColor = Utils.getColorAttr(mView.getContext(),
+ android.R.attr.textColorPrimary).getDefaultColor();
+ mPasswordEntry.setTextColor(textColor);
+ mPasswordEntry.setHighlightColor(textColor);
+ mPasswordEntry.setBackgroundTintList(ColorStateList.valueOf(textColor));
+ mPasswordEntry.setForegroundTintList(ColorStateList.valueOf(textColor));
+ mSwitchImeButton.setImageTintList(ColorStateList.valueOf(textColor));
+ }
+
protected KeyguardPasswordViewController(KeyguardPasswordView view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
SecurityMode securityMode,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 730c17787908..2aaf748e2415 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -33,6 +33,7 @@ import com.android.internal.widget.LockPatternView.Cell;
import com.android.internal.widget.LockscreenCredential;
import com.android.keyguard.EmergencyButton.EmergencyButtonCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import java.util.List;
@@ -197,6 +198,7 @@ public class KeyguardPatternViewController
@Override
protected void onViewAttached() {
+ super.onViewAttached();
mLockPatternView.setOnPatternListener(new UnlockPatternListener());
mLockPatternView.setSaveEnabled(false);
mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
@@ -252,6 +254,16 @@ public class KeyguardPatternViewController
}
@Override
+ public void reloadColors() {
+ super.reloadColors();
+ mMessageAreaController.reloadColors();
+ int textColor = Utils.getColorAttr(mLockPatternView.getContext(),
+ android.R.attr.textColorPrimary).getDefaultColor();
+ int errorColor = Utils.getColorError(mLockPatternView.getContext()).getDefaultColor();
+ mLockPatternView.setColors(textColor, textColor, errorColor);
+ }
+
+ @Override
public void onPause() {
super.onPause();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 7fa43116a7b1..4ddfccb21c73 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -24,12 +24,16 @@ import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
import android.view.View;
+import android.widget.ImageButton;
import com.android.internal.widget.LockscreenCredential;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
/**
@@ -39,8 +43,9 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
protected PasswordTextView mPasswordEntry;
private View mOkButton;
- private View mDeleteButton;
- private View[] mButtons = new View[10];
+ private ImageButton mDeleteButton;
+ private NumPadKey[] mButtons = new NumPadKey[10];
+ private View mDivider;
public KeyguardPinBasedInputView(Context context) {
this(context, null);
@@ -147,6 +152,7 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
mDeleteButton = findViewById(R.id.delete_button);
mDeleteButton.setVisibility(View.VISIBLE);
+ mDivider = findViewById(R.id.divider);
mButtons[0] = findViewById(R.id.key0);
mButtons[1] = findViewById(R.id.key1);
@@ -161,6 +167,26 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
mPasswordEntry.requestFocus();
super.onFinishInflate();
+ reloadColors();
+ }
+
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ for (NumPadKey key : mButtons) {
+ key.reloadColors();
+ }
+ mPasswordEntry.reloadColors();
+ int deleteColor = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary)
+ .getDefaultColor();
+ mDeleteButton.setImageTintList(ColorStateList.valueOf(deleteColor));
+ mDivider.setBackground(getContext().getDrawable(R.drawable.pin_divider));
+
+ ContextThemeWrapper themedContext = new ContextThemeWrapper(mContext,
+ R.style.Widget_TextView_NumPadKey);
+ mDeleteButton.setBackground(themedContext.getDrawable(R.drawable.ripple_drawable_pin));
+ mOkButton.setBackground(themedContext.getDrawable(R.drawable.ripple_drawable_pin));
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 6769436be8ef..fb0d6beca513 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -53,6 +53,12 @@ public class KeyguardPinViewController
}
@Override
+ public void reloadColors() {
+ super.reloadColors();
+ mView.reloadColors();
+ }
+
+ @Override
void resetState() {
super.resetState();
mMessageAreaController.setMessage("");
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 9a511502b475..1a8d420fb394 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -47,6 +47,7 @@ import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
@@ -69,6 +70,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private final KeyguardStateController mKeyguardStateController;
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
private final SecurityCallback mSecurityCallback;
+ private final ConfigurationController mConfigurationController;
private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
@@ -144,6 +146,18 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
}
};
+ private ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onOverlayChanged() {
+ mSecurityViewFlipperController.reloadColors();
+ }
+
+ @Override
+ public void onUiModeChanged() {
+ mSecurityViewFlipperController.reloadColors();
+ }
+ };
private KeyguardSecurityContainerController(KeyguardSecurityContainer view,
AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
@@ -154,7 +168,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
UiEventLogger uiEventLogger,
KeyguardStateController keyguardStateController,
SecurityCallback securityCallback,
- KeyguardSecurityViewFlipperController securityViewFlipperController) {
+ KeyguardSecurityViewFlipperController securityViewFlipperController,
+ ConfigurationController configurationController) {
super(view);
mLockPatternUtils = lockPatternUtils;
mUpdateMonitor = keyguardUpdateMonitor;
@@ -166,6 +181,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mSecurityViewFlipperController = securityViewFlipperController;
mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
mKeyguardSecurityCallback);
+ mConfigurationController = configurationController;
}
@Override
@@ -176,10 +192,12 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
@Override
protected void onViewAttached() {
mView.setSwipeListener(mSwipeListener);
+ mConfigurationController.addCallback(mConfigurationListener);
}
@Override
protected void onViewDetached() {
+ mConfigurationController.removeCallback(mConfigurationListener);
}
/** */
@@ -459,6 +477,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private final UiEventLogger mUiEventLogger;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
+ private final ConfigurationController mConfigurationController;
@Inject
Factory(KeyguardSecurityContainer view,
@@ -470,7 +489,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
MetricsLogger metricsLogger,
UiEventLogger uiEventLogger,
KeyguardStateController keyguardStateController,
- KeyguardSecurityViewFlipperController securityViewFlipperController) {
+ KeyguardSecurityViewFlipperController securityViewFlipperController,
+ ConfigurationController configurationController) {
mView = view;
mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
mLockPatternUtils = lockPatternUtils;
@@ -480,6 +500,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mUiEventLogger = uiEventLogger;
mKeyguardStateController = keyguardStateController;
mSecurityViewFlipperController = securityViewFlipperController;
+ mConfigurationController = configurationController;
}
public KeyguardSecurityContainerController create(
@@ -487,7 +508,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
return new KeyguardSecurityContainerController(mView,
mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
- mKeyguardStateController, securityCallback, mSecurityViewFlipperController);
+ mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
+ mConfigurationController);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index 49530355a6fb..f1b504e9f941 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -71,6 +71,15 @@ public class KeyguardSecurityViewFlipperController
}
}
+ /**
+ * Reload colors of ui elements upon theme change.
+ */
+ public void reloadColors() {
+ for (KeyguardInputViewController<KeyguardInputView> child : mChildren) {
+ child.reloadColors();
+ }
+ }
+
@VisibleForTesting
KeyguardInputViewController<KeyguardInputView> getSecurityView(SecurityMode securityMode,
KeyguardSecurityCallback keyguardSecurityCallback) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 2cdd7f117594..5b4a7ff3e16e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -309,7 +309,7 @@ public class KeyguardSimPinViewController
Resources rez = mView.getResources();
String msg;
TypedArray array = mView.getContext().obtainStyledAttributes(
- new int[] { R.attr.wallpaperTextColor });
+ new int[] { android.R.attr.textColor });
int color = array.getColor(0, Color.WHITE);
array.recycle();
if (count < 2) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index adb4c13b74d5..eafb33f8195d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -189,7 +189,7 @@ public class KeyguardSimPukViewController
Resources rez = mView.getResources();
String msg;
TypedArray array = mView.getContext().obtainStyledAttributes(
- new int[] { R.attr.wallpaperTextColor });
+ new int[] { android.R.attr.textColor });
int color = array.getColor(0, Color.WHITE);
array.recycle();
if (count < 2) {
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 2205fdd4267d..a5182055e14d 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -18,9 +18,11 @@ package com.android.keyguard;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -30,6 +32,7 @@ import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
public class NumPadKey extends ViewGroup {
@@ -121,12 +124,29 @@ public class NumPadKey extends ViewGroup {
a = context.obtainStyledAttributes(attrs, android.R.styleable.View);
if (!a.hasValueOrEmpty(android.R.styleable.View_background)) {
- setBackground(mContext.getDrawable(R.drawable.ripple_drawable_pin));
+ Drawable rippleDrawable = new ContextThemeWrapper(mContext,
+ R.style.Widget_TextView_NumPadKey).getDrawable(R.drawable.ripple_drawable_pin);
+ setBackground(rippleDrawable);
}
a.recycle();
setContentDescription(mDigitText.getText().toString());
}
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ int textColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary)
+ .getDefaultColor();
+ int klondikeColor = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary)
+ .getDefaultColor();
+ mDigitText.setTextColor(textColor);
+ mKlondikeText.setTextColor(klondikeColor);
+ Drawable rippleDrawable = new ContextThemeWrapper(mContext,
+ R.style.Widget_TextView_NumPadKey).getDrawable(R.drawable.ripple_drawable_pin);
+ setBackground(rippleDrawable);
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
index c92174a0d8af..5ffc2836b9e3 100644
--- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
@@ -42,6 +42,7 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.EditText;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import java.util.ArrayList;
@@ -131,8 +132,8 @@ public class PasswordTextView extends View {
mCharPadding = a.getDimensionPixelSize(R.styleable.PasswordTextView_charPadding,
getContext().getResources().getDimensionPixelSize(
R.dimen.password_char_padding));
- int textColor = a.getColor(R.styleable.PasswordTextView_android_textColor, Color.WHITE);
- mDrawPaint.setColor(textColor);
+ mDrawPaint.setColor(a.getColor(R.styleable.PasswordTextView_android_textColor,
+ Color.WHITE));
} finally {
a.recycle();
}
@@ -184,6 +185,15 @@ public class PasswordTextView extends View {
}
}
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ int textColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary)
+ .getDefaultColor();
+ mDrawPaint.setColor(textColor);
+ }
+
@Override
public boolean hasOverlappingRendering() {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index 70a57cc8bd2a..e24a513437ea 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,44 +14,39 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS;
+import static com.android.systemui.classifier.FalsingModule.BRIGHT_LINE_GESTURE_CLASSIFERS;
-import android.app.ActivityManager;
-import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.view.MotionEvent;
-import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.R;
-import com.android.systemui.classifier.Classifier;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
-import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dagger.qualifiers.TestHarness;
import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.phone.NotificationTapHelper;
-import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.sensors.ThresholdSensor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayDeque;
-import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Queue;
+import java.util.Set;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import javax.inject.Inject;
+import javax.inject.Named;
/**
* FalsingManager designed to make clear why a touch was rejected.
@@ -68,6 +63,7 @@ public class BrightLineFalsingManager implements FalsingManager {
private final DockManager mDockManager;
private final SingleTapClassifier mSingleTapClassifier;
private final DoubleTapClassifier mDoubleTapClassifier;
+ private final boolean mTestHarness;
private final MetricsLogger mMetricsLogger;
private int mIsFalseTouchCalls;
private static final Queue<String> RECENT_INFO_LOG =
@@ -75,7 +71,7 @@ public class BrightLineFalsingManager implements FalsingManager {
private static final Queue<DebugSwipeRecord> RECENT_SWIPES =
new ArrayDeque<>(RECENT_SWIPE_LOG_SIZE + 1);
- private final List<FalsingClassifier> mClassifiers;
+ private final Collection<FalsingClassifier> mClassifiers;
private final SessionListener mSessionListener = new SessionListener() {
@Override
@@ -93,29 +89,17 @@ public class BrightLineFalsingManager implements FalsingManager {
@Inject
public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
- DeviceConfigProxy deviceConfigProxy, @Main Resources resources,
- ViewConfiguration viewConfiguration, DockManager dockManager) {
+ DockManager dockManager, MetricsLogger metricsLogger,
+ @Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers,
+ SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier,
+ @TestHarness boolean testHarness) {
mDataProvider = falsingDataProvider;
mDockManager = dockManager;
-
- mMetricsLogger = new MetricsLogger();
- mClassifiers = new ArrayList<>();
- DistanceClassifier distanceClassifier =
- new DistanceClassifier(mDataProvider, deviceConfigProxy);
- ProximityClassifier proximityClassifier =
- new ProximityClassifier(distanceClassifier, mDataProvider, deviceConfigProxy);
- mClassifiers.add(new PointerCountClassifier(mDataProvider));
- mClassifiers.add(new TypeClassifier(mDataProvider));
- mClassifiers.add(new DiagonalClassifier(mDataProvider, deviceConfigProxy));
- mClassifiers.add(distanceClassifier);
- mClassifiers.add(proximityClassifier);
- mClassifiers.add(new ZigZagClassifier(mDataProvider, deviceConfigProxy));
-
- mSingleTapClassifier = new SingleTapClassifier(
- mDataProvider, viewConfiguration.getScaledTouchSlop());
- mDoubleTapClassifier = new DoubleTapClassifier(mDataProvider, mSingleTapClassifier,
- resources.getDimension(R.dimen.double_tap_slop),
- NotificationTapHelper.DOUBLE_TAP_TIMEOUT_MS);
+ mMetricsLogger = metricsLogger;
+ mClassifiers = classifiers;
+ mSingleTapClassifier = singleTapClassifier;
+ mDoubleTapClassifier = doubleTapClassifier;
+ mTestHarness = testHarness;
mDataProvider.addSessionListener(mSessionListener);
}
@@ -132,7 +116,7 @@ public class BrightLineFalsingManager implements FalsingManager {
return mPreviousResult;
}
- mPreviousResult = !ActivityManager.isRunningInUserTestHarness()
+ mPreviousResult = !mTestHarness
&& !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()
&& mClassifiers.stream().anyMatch(falsingClassifier -> {
boolean result = falsingClassifier.isFalseTouch();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
index a73ccf575249..92dd8b74e959 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE;
@@ -23,11 +23,12 @@ import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
import android.provider.DeviceConfig;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.Locale;
+import javax.inject.Inject;
+
/**
* False on swipes that are too close to 45 degrees.
*
@@ -47,6 +48,7 @@ class DiagonalClassifier extends FalsingClassifier {
private final float mHorizontalAngleRange;
private final float mVerticalAngleRange;
+ @Inject
DiagonalClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
super(dataProvider);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
index 524d524f38b6..50d55f6f6028 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_FLING_THRESHOLD_IN;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_SWIPE_THRESHOLD_IN;
@@ -27,12 +27,13 @@ import android.provider.DeviceConfig;
import android.view.MotionEvent;
import android.view.VelocityTracker;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.List;
import java.util.Locale;
+import javax.inject.Inject;
+
/**
* Ensure that the swipe + momentum covers a minimum distance.
*/
@@ -54,6 +55,7 @@ class DistanceClassifier extends FalsingClassifier {
private boolean mDistanceDirty;
private DistanceVectors mCachedDistance;
+ @Inject
DistanceClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
super(dataProvider);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
index a27ea6172414..1c8f4208edba 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
@@ -14,15 +14,19 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
-import android.view.MotionEvent;
+import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS;
+import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TOUCH_SLOP;
-import com.android.systemui.classifier.FalsingDataProvider;
+import android.view.MotionEvent;
import java.util.List;
import java.util.Queue;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* Returns a false touch if the most two recent gestures are not taps or are too far apart.
*/
@@ -34,8 +38,10 @@ public class DoubleTapClassifier extends FalsingClassifier {
private StringBuilder mReason = new StringBuilder();
+ @Inject
DoubleTapClassifier(FalsingDataProvider dataProvider, SingleTapClassifier singleTapClassifier,
- float doubleTapSlop, long doubleTapTimeMs) {
+ @Named(DOUBLE_TAP_TOUCH_SLOP) float doubleTapSlop,
+ @Named(DOUBLE_TAP_TIMEOUT_MS) long doubleTapTimeMs) {
super(dataProvider);
mSingleTapClassifier = singleTapClassifier;
mDoubleTapSlop = doubleTapSlop;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
index 568dc432729f..82575c3e639e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,12 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import android.view.MotionEvent;
-import com.android.systemui.classifier.Classifier;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.sensors.ProximitySensor;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index b29871c1c3d0..009b311f2363 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -21,9 +21,6 @@ import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
-import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
-import com.android.systemui.classifier.brightline.FalsingClassifier;
-import com.android.systemui.classifier.brightline.TimeLimitedMotionEventBuffer;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.time.SystemClock;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 74629411c13d..d4f58c324d39 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -24,7 +24,6 @@ import android.view.MotionEvent;
import androidx.annotation.NonNull;
import com.android.systemui.Dumpable;
-import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
index 937bcbaa6222..7b7f17e1568b 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
@@ -16,16 +16,69 @@
package com.android.systemui.classifier;
+import android.content.res.Resources;
+import android.view.ViewConfiguration;
+
+import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.phone.NotificationTapHelper;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.inject.Named;
import dagger.Binds;
import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.ElementsIntoSet;
/** Dagger Module for Falsing. */
@Module
public interface FalsingModule {
+ String BRIGHT_LINE_GESTURE_CLASSIFERS = "bright_line_gesture_classifiers";
+ String SINGLE_TAP_TOUCH_SLOP = "falsing_single_tap_touch_slop";
+ String DOUBLE_TAP_TOUCH_SLOP = "falsing_double_tap_touch_slop";
+ String DOUBLE_TAP_TIMEOUT_MS = "falsing_double_tap_timeout_ms";
+
/** */
@Binds
@SysUISingleton
FalsingCollector bindsFalsingCollector(FalsingCollectorImpl impl);
+
+ /** */
+ @Provides
+ @ElementsIntoSet
+ @Named(BRIGHT_LINE_GESTURE_CLASSIFERS)
+ static Set<FalsingClassifier> providesBrightLineGestureClassifiers(
+ DistanceClassifier distanceClassifier, ProximityClassifier proximityClassifier,
+ PointerCountClassifier pointerCountClassifier, TypeClassifier typeClassifier,
+ DiagonalClassifier diagonalClassifier, ZigZagClassifier zigZagClassifier) {
+ return new HashSet<>(Arrays.asList(
+ pointerCountClassifier, typeClassifier, diagonalClassifier, distanceClassifier,
+ proximityClassifier, zigZagClassifier));
+ }
+
+ /** */
+ @Provides
+ @Named(DOUBLE_TAP_TIMEOUT_MS)
+ static long providesDoubleTapTimeoutMs() {
+ return NotificationTapHelper.DOUBLE_TAP_TIMEOUT_MS;
+ }
+
+ /** */
+ @Provides
+ @Named(DOUBLE_TAP_TOUCH_SLOP)
+ static float providesDoubleTapTouchSlop(@Main Resources resources) {
+ return resources.getDimension(R.dimen.double_tap_slop);
+ }
+
+ /** */
+ @Provides
+ @Named(SINGLE_TAP_TOUCH_SLOP)
+ static float providesSingleTapTouchSlop(ViewConfiguration viewConfiguration) {
+ return viewConfiguration.getScaledTouchSlop();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
index dd5d8a8f557b..0565165e1e8d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import android.view.MotionEvent;
-import com.android.systemui.classifier.FalsingDataProvider;
-
import java.util.Locale;
+import javax.inject.Inject;
+
/**
* False touch if more than one finger touches the screen.
*
@@ -37,6 +37,7 @@ class PointerCountClassifier extends FalsingClassifier {
private static final int MAX_ALLOWED_POINTERS_SWIPE_DOWN = 2;
private int mMaxPointerCount;
+ @Inject
PointerCountClassifier(FalsingDataProvider dataProvider) {
super(dataProvider);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
index 3551c241e71e..6e73fc06de4c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -22,12 +22,13 @@ import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import android.provider.DeviceConfig;
import android.view.MotionEvent;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.sensors.ProximitySensor;
import java.util.Locale;
+import javax.inject.Inject;
+
/**
* False touch if proximity sensor is covered for more than a certain percentage of the gesture.
@@ -47,10 +48,11 @@ class ProximityClassifier extends FalsingClassifier {
private long mNearDurationNs;
private float mPercentNear;
+ @Inject
ProximityClassifier(DistanceClassifier distanceClassifier,
FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
super(dataProvider);
- this.mDistanceClassifier = distanceClassifier;
+ mDistanceClassifier = distanceClassifier;
mPercentCoveredThreshold = deviceConfigProxy.getFloat(
DeviceConfig.NAMESPACE_SYSTEMUI,
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
index 8c7648149e44..6b7a1413bc74 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
@@ -14,14 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
-import android.view.MotionEvent;
+import static com.android.systemui.classifier.FalsingModule.SINGLE_TAP_TOUCH_SLOP;
-import com.android.systemui.classifier.FalsingDataProvider;
+import android.view.MotionEvent;
import java.util.List;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* Falsing classifier that accepts or rejects a single gesture as a tap.
*/
@@ -29,7 +32,9 @@ public class SingleTapClassifier extends FalsingClassifier {
private final float mTouchSlop;
private String mReason;
- SingleTapClassifier(FalsingDataProvider dataProvider, float touchSlop) {
+ @Inject
+ SingleTapClassifier(FalsingDataProvider dataProvider,
+ @Named(SINGLE_TAP_TOUCH_SLOP) float touchSlop) {
super(dataProvider);
mTouchSlop = touchSlop;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
index 7430a1eda920..7969b4e83ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import android.view.MotionEvent;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
index f62871f383b3..711a0fc0f478 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
@@ -26,12 +26,13 @@ import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
import static com.android.systemui.classifier.Classifier.UNLOCK;
-import com.android.systemui.classifier.FalsingDataProvider;
+import javax.inject.Inject;
/**
* Ensure that the swipe direction generally matches that of the interaction type.
*/
public class TypeClassifier extends FalsingClassifier {
+ @Inject
TypeClassifier(FalsingDataProvider dataProvider) {
super(dataProvider);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
index 9ca77d364bc4..383dda498b49 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_PRIMARY_DEVIANCE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE;
@@ -25,13 +25,14 @@ import android.graphics.Point;
import android.provider.DeviceConfig;
import android.view.MotionEvent;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
+import javax.inject.Inject;
+
/**
* Penalizes gestures that change direction in either the x or y too much.
*/
@@ -56,6 +57,7 @@ class ZigZagClassifier extends FalsingClassifier {
private float mLastMaxXDeviance;
private float mLastMaxYDeviance;
+ @Inject
ZigZagClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
super(dataProvider);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 7127f26a7ed2..275bfaa1023c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -30,7 +30,6 @@ import android.os.HandlerThread;
import android.os.Looper;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.util.DisplayMetrics;
import android.view.Choreographer;
import android.view.IWindowManager;
import android.view.LayoutInflater;
@@ -141,16 +140,6 @@ public class DependencyProvider {
return networkController.getDataSaverController();
}
- /** */
- @Provides
- @SysUISingleton
- public DisplayMetrics provideDisplayMetrics(Context context, WindowManager windowManager) {
- DisplayMetrics displayMetrics = new DisplayMetrics();
- context.getDisplay().getMetrics(displayMetrics);
- return displayMetrics;
- }
-
- /** */
@Provides
@SysUISingleton
public INotificationManager provideINotificationManager() {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index 53383d65e379..a89c7acea984 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -16,13 +16,14 @@
package com.android.systemui.dagger;
+import android.app.ActivityManager;
import android.content.Context;
import android.util.DisplayMetrics;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
+import com.android.systemui.dagger.qualifiers.TestHarness;
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
-import com.android.wm.shell.animation.FlingAnimationUtils;
import javax.inject.Singleton;
@@ -49,15 +50,12 @@ import dagger.Provides;
GlobalConcurrencyModule.class})
public class GlobalModule {
- // TODO(b/162923491): This should not be a singleton at all, the display metrics can change and
- // callers should be creating a new builder on demand
- @Singleton
+ /** */
@Provides
- static FlingAnimationUtils.Builder provideFlingAnimationUtilsBuilder(
- Context context) {
+ public DisplayMetrics provideDisplayMetrics(Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
context.getDisplay().getMetrics(displayMetrics);
- return new FlingAnimationUtils.Builder(displayMetrics);
+ return displayMetrics;
}
/** Provides an instance of {@link com.android.internal.logging.UiEventLogger} */
@@ -66,4 +64,10 @@ public class GlobalModule {
static UiEventLogger provideUiEventLogger() {
return new UiEventLoggerImpl();
}
+
+ @Provides
+ @TestHarness
+ static boolean provideIsTestHarness() {
+ return ActivityManager.isRunningInUserTestHarness();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java
new file mode 100644
index 000000000000..f68ab188c93c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 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.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+
+/**
+ * An annotation for injecting whether or not we are running in a test environment.
+ */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface TestHarness {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LogConfig.java b/packages/SystemUI/src/com/android/systemui/screenshot/LogConfig.java
new file mode 100644
index 000000000000..6050c2b90e34
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LogConfig.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+@SuppressWarnings("PointlessBooleanExpression")
+class LogConfig {
+
+ /** Log ALL the things... */
+ private static final boolean DEBUG_ALL = false;
+
+ /** Default log logTag for screenshot code */
+ private static final String TAG_SS = "Screenshot";
+
+ /** Use class name as Log tag instead of the default */
+ private static final boolean TAG_WITH_CLASS_NAME = false;
+
+ /** Action creation and user selection: Share, Save, Edit, Delete, Smart action, etc */
+ static final boolean DEBUG_ACTIONS = DEBUG_ALL || false;
+
+ /** Debug info about animations such as start, complete and cancel */
+ static final boolean DEBUG_ANIM = DEBUG_ALL || false;
+
+ /** Whenever Uri is supplied to consumer, or onComplete runnable is run() */
+ static final boolean DEBUG_CALLBACK = DEBUG_ALL || false;
+
+ /** Logs information about dismissing the screenshot tool */
+ static final boolean DEBUG_DISMISS = DEBUG_ALL || false;
+
+ /** Touch or key event driven action or side effects */
+ static final boolean DEBUG_INPUT = DEBUG_ALL || false;
+
+ /** Scroll capture usage */
+ static final boolean DEBUG_SCROLL = DEBUG_ALL || false;
+
+ /** Service lifecycle events and callbacks */
+ static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
+
+ /** Storage related actions, Bitmap.compress, ContentManager, etc */
+ static final boolean DEBUG_STORAGE = DEBUG_ALL || false;
+
+ /** High level logical UI actions: timeout, onConfigChanged, insets, show actions, reset */
+ static final boolean DEBUG_UI = DEBUG_ALL || false;
+
+ /** Interactions with Window and WindowManager */
+ static final boolean DEBUG_WINDOW = DEBUG_ALL || false;
+
+ static String logTag(Class<?> cls) {
+ return TAG_WITH_CLASS_NAME ? cls.getSimpleName() : TAG_SS;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index b2ebf3f700b9..f4ce77acb8ec 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -16,6 +16,11 @@
package com.android.systemui.screenshot;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_STORAGE;
+import static com.android.systemui.screenshot.LogConfig.logTag;
+
import android.app.ActivityTaskManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -45,7 +50,7 @@ import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.text.TextUtils;
import android.text.format.DateUtils;
-import android.util.Slog;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -73,8 +78,8 @@ import java.util.concurrent.CompletableFuture;
/**
* An AsyncTask that saves an image to the media store in the background.
*/
-class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
- private static final String TAG = "SaveImageInBackgroundTask";
+class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
+ private static final String TAG = logTag(SaveImageInBackgroundTask.class);
private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
private static final String SCREENSHOT_ID_TEMPLATE = "Screenshot_%s";
@@ -121,6 +126,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... paramsUnused) {
if (isCancelled()) {
+ if (DEBUG_STORAGE) {
+ Log.d(TAG, "cancelled! returning null");
+ }
return null;
}
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
@@ -151,9 +159,19 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
try {
// First, write the actual data for our screenshot
try (OutputStream out = resolver.openOutputStream(uri)) {
+ if (DEBUG_STORAGE) {
+ Log.d(TAG, "Compressing PNG:"
+ + " w=" + image.getWidth() + " h=" + image.getHeight());
+ }
if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
+ if (DEBUG_STORAGE) {
+ Log.d(TAG, "Bitmap.compress returned false");
+ }
throw new IOException("Failed to compress");
}
+ if (DEBUG_STORAGE) {
+ Log.d(TAG, "Done compressing PNG");
+ }
}
// Next, write metadata to help index the screenshot
@@ -181,7 +199,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL,
DateTimeFormatter.ofPattern("XXX").format(time));
}
-
+ if (DEBUG_STORAGE) {
+ Log.d(TAG, "Writing EXIF metadata");
+ }
exif.saveAttributes();
}
@@ -190,6 +210,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
values.put(MediaColumns.IS_PENDING, 0);
values.putNull(MediaColumns.DATE_EXPIRES);
resolver.update(uri, values, null, null);
+ if (DEBUG_STORAGE) {
+ Log.d(TAG, "Completed writing to ContentManager");
+ }
} catch (Exception e) {
resolver.delete(uri, null);
throw e;
@@ -215,15 +238,24 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri);
mParams.mActionsReadyListener.onActionsReady(mImageData);
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "finished background processing, Calling (Consumer<Uri>) "
+ + "finisher.accept(\"" + mImageData.uri + "\"");
+ }
mParams.finisher.accept(mImageData.uri);
mParams.image = null;
} catch (Exception e) {
// IOException/UnsupportedOperationException may be thrown if external storage is
// not mounted
- Slog.e(TAG, "unable to save screenshot", e);
+ if (DEBUG_STORAGE) {
+ Log.d(TAG, "Failed to store screenshot", e);
+ }
mParams.clearImage();
mImageData.reset();
mParams.mActionsReadyListener.onActionsReady(mImageData);
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "Calling (Consumer<Uri>) finisher.accept(null)");
+ }
mParams.finisher.accept(null);
}
@@ -245,6 +277,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
// params from the ctor in any case.
mImageData.reset();
mParams.mActionsReadyListener.onActionsReady(mImageData);
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "onCancelled, calling (Consumer<Uri>) finisher.accept(null)");
+ }
mParams.finisher.accept(null);
mParams.clearImage();
}
@@ -380,7 +415,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
try {
return ActivityTaskManager.getService().getLastResumedActivityUserId();
} catch (RemoteException e) {
- Slog.w(TAG, "getUserHandleOfForegroundApplication: ", e);
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, "Failed to get UserHandle of foreground app: ", e);
+ }
return context.getUserId();
}
}
@@ -421,6 +458,4 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
.putExtra(ScreenshotController.EXTRA_ID, screenshotId)
.putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED, smartActionsEnabled);
}
-
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 1e916739ca9b..6a4e93be0fe5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -16,22 +16,28 @@
package com.android.systemui.screenshot;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_UI;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW;
+import static com.android.systemui.screenshot.LogConfig.logTag;
+
import static java.util.Objects.requireNonNull;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Context;
-import android.content.res.Configuration;
+import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.PixelFormat;
@@ -64,6 +70,7 @@ import android.widget.Toast;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
+import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.R;
import com.android.systemui.util.DeviceConfigProxy;
@@ -76,6 +83,7 @@ import javax.inject.Inject;
* Controls the state and flow for screenshots.
*/
public class ScreenshotController {
+ private static final String TAG = logTag(ScreenshotController.class);
/**
* POD used in the AsyncTask which saves an image in the background.
*/
@@ -111,12 +119,10 @@ public class ScreenshotController {
}
}
- abstract static class ActionsReadyListener {
- abstract void onActionsReady(ScreenshotController.SavedImageData imageData);
+ interface ActionsReadyListener {
+ void onActionsReady(ScreenshotController.SavedImageData imageData);
}
- private static final String TAG = "ScreenshotController";
-
// These strings are used for communicating the action invoked to
// ScreenshotNotificationSmartActionsProvider.
static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type";
@@ -145,7 +151,6 @@ public class ScreenshotController {
private final WindowManager mWindowManager;
private final WindowManager.LayoutParams mWindowLayoutParams;
- private final Display mDisplay;
private final DisplayMetrics mDisplayMetrics;
private final AccessibilityManager mAccessibilityManager;
private final MediaActionSound mCameraSound;
@@ -162,15 +167,15 @@ public class ScreenshotController {
private Animator mScreenshotAnimation;
private Runnable mOnCompleteRunnable;
- private boolean mInDarkMode;
- private boolean mDirectionLTR;
- private boolean mOrientationPortrait;
private final Handler mScreenshotHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_CORNER_TIMEOUT:
+ if (DEBUG_UI) {
+ Log.d(TAG, "Corner timeout hit");
+ }
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT);
ScreenshotController.this.dismissScreenshot(false);
break;
@@ -180,6 +185,15 @@ public class ScreenshotController {
}
};
+ /** Tracks config changes that require re-creating UI */
+ private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
+ ActivityInfo.CONFIG_ORIENTATION
+ | ActivityInfo.CONFIG_LAYOUT_DIRECTION
+ | ActivityInfo.CONFIG_LOCALE
+ | ActivityInfo.CONFIG_UI_MODE
+ | ActivityInfo.CONFIG_SCREEN_LAYOUT
+ | ActivityInfo.CONFIG_ASSETS_PATHS);
+
@Inject
ScreenshotController(
Context context,
@@ -194,23 +208,20 @@ public class ScreenshotController {
mUiEventLogger = uiEventLogger;
final DisplayManager dm = requireNonNull(context.getSystemService(DisplayManager.class));
- mDisplay = dm.getDisplay(DEFAULT_DISPLAY);
- mContext = context.createWindowContext(TYPE_SCREENSHOT, null);
+ final Display display = dm.getDisplay(DEFAULT_DISPLAY);
+ final Context displayContext = context.createDisplayContext(display);
+ mContext = displayContext.createWindowContext(TYPE_SCREENSHOT, null);
mWindowManager = mContext.getSystemService(WindowManager.class);
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
mConfigProxy = configProxy;
- Configuration config = mContext.getResources().getConfiguration();
- mInDarkMode = config.isNightModeActive();
- mDirectionLTR = config.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
- mOrientationPortrait = config.orientation == ORIENTATION_PORTRAIT;
mWindowToken = new Binder("ScreenshotController");
mScrollCaptureClient.setHostWindowToken(mWindowToken);
// Setup the window that we are going to use
- mWindowLayoutParams = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT, 0, 0,
- TYPE_SCREENSHOT,
+ mWindowLayoutParams = new WindowManager.LayoutParams(
+ MATCH_PARENT, MATCH_PARENT, /* xpos */ 0, /* ypos */ 0, TYPE_SCREENSHOT,
WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -235,7 +246,7 @@ public class ScreenshotController {
reloadAssets();
mDisplayMetrics = new DisplayMetrics();
- mDisplay.getRealMetrics(mDisplayMetrics);
+ display.getRealMetrics(mDisplayMetrics);
// Setup the Camera shutter sound
mCameraSound = new MediaActionSound();
@@ -245,7 +256,6 @@ public class ScreenshotController {
void takeScreenshotFullscreen(Consumer<Uri> finisher, Runnable onComplete) {
mOnCompleteRunnable = onComplete;
- mDisplay.getRealMetrics(mDisplayMetrics);
takeScreenshotInternal(
finisher,
new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
@@ -266,19 +276,18 @@ public class ScreenshotController {
return;
}
- if (aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
- saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, false);
- } else {
- saveScreenshot(screenshot, finisher,
- new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()), Insets.NONE,
- true);
+ boolean showFlash = false;
+ if (!aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
+ showFlash = true;
+ visibleInsets = Insets.NONE;
+ screenshotScreenBounds.set(0, 0, screenshot.getWidth(), screenshot.getHeight());
}
+ saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, showFlash);
}
/**
* Displays a screenshot selector
*/
- @SuppressLint("ClickableViewAccessibility")
void takeScreenshotPartial(final Consumer<Uri> finisher, Runnable onComplete) {
dismissScreenshot(true);
mOnCompleteRunnable = onComplete;
@@ -293,13 +302,17 @@ public class ScreenshotController {
* Clears current screenshot
*/
void dismissScreenshot(boolean immediate) {
+ if (DEBUG_DISMISS) {
+ Log.d(TAG, "dismissScreenshot(immediate=" + immediate + ")");
+ }
// If we're already animating out, don't restart the animation
// (but do obey an immediate dismissal)
if (!immediate && mScreenshotView.isDismissing()) {
- Log.v(TAG, "Already dismissing, ignoring duplicate command");
+ if (DEBUG_DISMISS) {
+ Log.v(TAG, "Already dismissing, ignoring duplicate command");
+ }
return;
}
- Log.v(TAG, "Clearing screenshot");
mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
if (immediate) {
resetScreenshotView();
@@ -308,73 +321,25 @@ public class ScreenshotController {
}
}
- private void onConfigChanged(Configuration newConfig) {
- boolean needsUpdate = false;
- // dark mode
- if (newConfig.isNightModeActive()) {
- // Night mode is active, we're using dark theme
- if (!mInDarkMode) {
- mInDarkMode = true;
- needsUpdate = true;
- }
- } else {
- // Night mode is not active, we're using the light theme
- if (mInDarkMode) {
- mInDarkMode = false;
- needsUpdate = true;
- }
- }
-
- // RTL configuration
- switch (newConfig.getLayoutDirection()) {
- case View.LAYOUT_DIRECTION_LTR:
- if (!mDirectionLTR) {
- mDirectionLTR = true;
- needsUpdate = true;
- }
- break;
- case View.LAYOUT_DIRECTION_RTL:
- if (mDirectionLTR) {
- mDirectionLTR = false;
- needsUpdate = true;
- }
- break;
- }
-
- // portrait/landscape orientation
- switch (newConfig.orientation) {
- case ORIENTATION_PORTRAIT:
- if (!mOrientationPortrait) {
- mOrientationPortrait = true;
- needsUpdate = true;
- }
- break;
- case ORIENTATION_LANDSCAPE:
- if (mOrientationPortrait) {
- mOrientationPortrait = false;
- needsUpdate = true;
- }
- break;
- }
-
- if (needsUpdate) {
- reloadAssets();
- }
- }
-
/**
- * Update assets (called when the dark theme status changes). We only need to update the dismiss
- * button and the actions container background, since the buttons are re-inflated on demand.
+ * Update resources on configuration change. Reinflate for theme/color changes.
*/
private void reloadAssets() {
+ if (DEBUG_UI) {
+ Log.d(TAG, "reloadAssets()");
+ }
boolean wasAttached = mDecorView.isAttachedToWindow();
if (wasAttached) {
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "Removing screenshot window");
+ }
mWindowManager.removeView(mDecorView);
}
// respect the display cutout in landscape (since we'd otherwise overlap) but not portrait
+ int orientation = mContext.getResources().getConfiguration().orientation;
mWindowLayoutParams.setFitInsetsTypes(
- mOrientationPortrait ? 0 : WindowInsets.Type.displayCutout());
+ orientation == ORIENTATION_PORTRAIT ? 0 : WindowInsets.Type.displayCutout());
// ignore system bar insets for the purpose of window layout
mDecorView.setOnApplyWindowInsetsListener((v, insets) -> v.onApplyWindowInsets(
@@ -390,6 +355,9 @@ public class ScreenshotController {
// TODO(159460485): Remove this when focus is handled properly in the system
mScreenshotView.setOnTouchListener((v, event) -> {
if (event.getActionMasked() == MotionEvent.ACTION_OUTSIDE) {
+ if (DEBUG_INPUT) {
+ Log.d(TAG, "onTouch: ACTION_OUTSIDE");
+ }
// Once the user touches outside, stop listening for input
setWindowFocusable(false);
}
@@ -398,6 +366,9 @@ public class ScreenshotController {
mScreenshotView.setOnKeyListener((v, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (DEBUG_INPUT) {
+ Log.d(TAG, "onKeyEvent: KeyEvent.KEYCODE_BACK");
+ }
dismissScreenshot(false);
return true;
}
@@ -427,10 +398,16 @@ public class ScreenshotController {
Bitmap screenshot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
if (screenshot == null) {
- Log.e(TAG, "Screenshot bitmap was null");
+ Log.e(TAG, "takeScreenshotInternal: Screenshot bitmap was null");
mNotificationsController.notifyScreenshotError(
R.string.screenshot_failed_to_capture_text);
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "Supplying null to Consumer<Uri>");
+ }
finisher.accept(null);
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "Calling mOnCompleteRunnable.run()");
+ }
mOnCompleteRunnable.run();
return;
}
@@ -453,12 +430,17 @@ public class ScreenshotController {
if (!mScreenshotView.isDismissing()) {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED);
}
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "saveScreenshot: screenshotView is already attached, resetting. "
+ + "(dismissing=" + mScreenshotView.isDismissing() + ")");
+ }
mScreenshotView.reset();
}
mScreenBitmap = screenshot;
if (!isUserSetupComplete()) {
+ Log.w(TAG, "User setup not complete, displaying toast only");
// User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
// and sharing shouldn't be exposed to the user.
saveScreenshotAndToast(finisher);
@@ -469,7 +451,12 @@ public class ScreenshotController {
mScreenBitmap.setHasAlpha(false);
mScreenBitmap.prepareToDraw();
- onConfigChanged(mContext.getResources().getConfiguration());
+ if (mConfigChanges.applyNewConfig(mContext.getResources())) {
+ if (DEBUG_UI) {
+ Log.d(TAG, "saveScreenshot: reloading assets");
+ }
+ reloadAssets();
+ }
// The window is focusable by default
setWindowFocusable(true);
@@ -502,25 +489,21 @@ public class ScreenshotController {
mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
});
- saveScreenshotInWorkerThread(finisher,
- new ScreenshotController.ActionsReadyListener() {
- @Override
- void onActionsReady(ScreenshotController.SavedImageData imageData) {
- finisher.accept(imageData.uri);
- if (imageData.uri == null) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED);
- mNotificationsController.notifyScreenshotError(
- R.string.screenshot_failed_to_save_text);
- } else {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED);
-
- mScreenshotHandler.post(() -> {
- Toast.makeText(mContext, R.string.screenshot_saved_title,
- Toast.LENGTH_SHORT).show();
- });
- }
- }
- });
+ saveScreenshotInWorkerThread(finisher, imageData -> {
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "returning URI to finisher (Consumer<URI>): " + imageData.uri);
+ }
+ finisher.accept(imageData.uri);
+ if (imageData.uri == null) {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED);
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_save_text);
+ } else {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED);
+ mScreenshotHandler.post(() -> Toast.makeText(mContext,
+ R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show());
+ }
+ });
}
/**
@@ -531,37 +514,46 @@ public class ScreenshotController {
mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
mScreenshotHandler.post(() -> {
if (!mScreenshotView.isAttachedToWindow()) {
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "Adding screenshot window");
+ }
mWindowManager.addView(mWindow.getDecorView(), mWindowLayoutParams);
}
mScreenshotView.prepareForAnimation(mScreenBitmap, screenInsets);
mScreenshotHandler.post(() -> {
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "adding OnComputeInternalInsetsListener");
+ }
mScreenshotView.getViewTreeObserver().addOnComputeInternalInsetsListener(
mScreenshotView);
mScreenshotAnimation =
mScreenshotView.createScreenshotDropInAnimation(screenRect, showFlash);
- saveScreenshotInWorkerThread(finisher,
- new ScreenshotController.ActionsReadyListener() {
- @Override
- void onActionsReady(
- ScreenshotController.SavedImageData imageData) {
- showUiOnActionsReady(imageData);
- }
- });
+ saveScreenshotInWorkerThread(finisher, this::showUiOnActionsReady);
// Play the shutter sound to notify that we've taken a screenshot
mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
+ if (DEBUG_ANIM) {
+ Log.d(TAG, "starting post-screenshot animation");
+ }
mScreenshotAnimation.start();
});
});
}
+ /** Reset screenshot view and then call onCompleteRunnable */
private void resetScreenshotView() {
+ if (DEBUG_UI) {
+ Log.d(TAG, "resetScreenshotView");
+ }
if (mScreenshotView.isAttachedToWindow()) {
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "Removing screenshot window");
+ }
mWindowManager.removeView(mDecorView);
}
mScreenshotView.reset();
@@ -571,8 +563,7 @@ public class ScreenshotController {
/**
* Creates a new worker thread and saves the screenshot to the media store.
*/
- private void saveScreenshotInWorkerThread(
- Consumer<Uri> finisher,
+ private void saveScreenshotInWorkerThread(Consumer<Uri> finisher,
@Nullable ScreenshotController.ActionsReadyListener actionsReadyListener) {
ScreenshotController.SaveImageInBackgroundData
data = new ScreenshotController.SaveImageInBackgroundData();
@@ -582,13 +573,7 @@ public class ScreenshotController {
if (mSaveInBgTask != null) {
// just log success/failure for the pre-existing screenshot
- mSaveInBgTask.setActionsReadyListener(
- new ScreenshotController.ActionsReadyListener() {
- @Override
- void onActionsReady(ScreenshotController.SavedImageData imageData) {
- logSuccessOnActionsReady(imageData);
- }
- });
+ mSaveInBgTask.setActionsReadyListener(this::logSuccessOnActionsReady);
}
mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data);
@@ -607,6 +592,9 @@ public class ScreenshotController {
SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS,
AccessibilityManager.FLAG_CONTENT_CONTROLS);
+ if (DEBUG_UI) {
+ Log.d(TAG, "Showing UI actions, dismiss timeout: " + timeoutMs + " ms");
+ }
mScreenshotHandler.sendMessageDelayed(
mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
timeoutMs);
@@ -652,6 +640,9 @@ public class ScreenshotController {
* shown.
*/
private void setWindowFocusable(boolean focusable) {
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "setWindowFocusable: " + focusable);
+ }
if (focusable) {
mWindowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
} else {
@@ -670,9 +661,10 @@ public class ScreenshotController {
if (insettedHeight == 0 || insettedWidth == 0 || bitmap.getWidth() == 0
|| bitmap.getHeight() == 0) {
- Log.e(TAG, String.format(
- "Provided bitmap and insets create degenerate region: %dx%d %s",
- bitmap.getWidth(), bitmap.getHeight(), bitmapInsets));
+ if (DEBUG_UI) {
+ Log.e(TAG, "Provided bitmap and insets create degenerate region: "
+ + bitmap.getWidth() + "x" + bitmap.getHeight() + " " + bitmapInsets);
+ }
return false;
}
@@ -680,11 +672,10 @@ public class ScreenshotController {
float boundsAspect = ((float) screenBounds.width()) / screenBounds.height();
boolean matchWithinTolerance = Math.abs(insettedBitmapAspect - boundsAspect) < 0.1f;
- if (!matchWithinTolerance) {
- Log.d(TAG, String.format("aspectRatiosMatch: don't match bitmap: %f, bounds: %f",
- insettedBitmapAspect, boundsAspect));
+ if (DEBUG_UI) {
+ Log.d(TAG, "aspectRatiosMatch: don't match bitmap: " + insettedBitmapAspect
+ + ", bounds: " + boundsAspect);
}
-
return matchWithinTolerance;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java
index 63f323ed2768..29f67f348f7b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java
@@ -16,6 +16,9 @@
package com.android.systemui.screenshot;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
+import static com.android.systemui.screenshot.LogConfig.logTag;
+
import android.app.Notification;
import android.content.ComponentName;
import android.graphics.Bitmap;
@@ -32,6 +35,9 @@ import java.util.concurrent.CompletableFuture;
* in order to provide smart actions in the screenshot notification.
*/
public class ScreenshotNotificationSmartActionsProvider {
+
+ private static final String TAG = logTag(ScreenshotNotificationSmartActionsProvider.class);
+
/* Key provided in the notification action to get the type of smart action. */
public static final String ACTION_TYPE = "action_type";
public static final String DEFAULT_ACTION_TYPE = "Smart Action";
@@ -51,29 +57,21 @@ public class ScreenshotNotificationSmartActionsProvider {
ERROR,
TIMEOUT
}
-
- private static final String TAG = "ScreenshotActions";
-
/**
* Default implementation that returns an empty list.
* This method is overridden in vendor-specific Sys UI implementation.
*
- * @param screenshotId A generated random unique id for the screenshot.
- * @param screenshotFileName name of the file where the screenshot will be written.
- * @param bitmap The bitmap of the screenshot. The bitmap config must be {@link
- * HARDWARE}.
- * @param componentName Contains package and activity class names where the screenshot was
- * taken. This is used as an additional signal to generate and rank
- * more relevant actions.
- * @param userHandle The user handle of the app where the screenshot was taken.
+ * @param screenshotId a unique id for the screenshot
+ * @param screenshotUri uri where the screenshot has been stored
+ * @param bitmap the screenshot, config must be {@link Bitmap.Config#HARDWARE}
+ * @param componentName name of the foreground component when the screenshot was taken
+ * @param userHandle user handle of the foreground task owner
*/
- public CompletableFuture<List<Notification.Action>> getActions(
- String screenshotId,
- Uri screenshotUri,
- Bitmap bitmap,
- ComponentName componentName,
- UserHandle userHandle) {
- Log.d(TAG, "Returning empty smart action list.");
+ public CompletableFuture<List<Notification.Action>> getActions(String screenshotId,
+ Uri screenshotUri, Bitmap bitmap, ComponentName componentName, UserHandle userHandle) {
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, "Returning empty smart action list.");
+ }
return CompletableFuture.completedFuture(Collections.emptyList());
}
@@ -88,7 +86,9 @@ public class ScreenshotNotificationSmartActionsProvider {
*/
public void notifyOp(String screenshotId, ScreenshotOp op, ScreenshotOpStatus status,
long durationMs) {
- Log.d(TAG, "Return without notify.");
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, "SmartActions: notifyOp() - return without notify");
+ }
}
/**
@@ -100,6 +100,8 @@ public class ScreenshotNotificationSmartActionsProvider {
* @param isSmartAction whether action invoked was a smart action.
*/
public void notifyAction(String screenshotId, String action, boolean isSmartAction) {
- Log.d(TAG, "Return without notify.");
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, "SmartActions: notifyAction: return without notify");
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java
index 468602a5369e..1184dc7fe1a4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java
@@ -18,6 +18,9 @@ package com.android.systemui.screenshot;
import static android.os.AsyncTask.THREAD_POOL_EXECUTOR;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
+import static com.android.systemui.screenshot.LogConfig.logTag;
+
import android.app.ActivityManager;
import android.app.Notification;
import android.content.ComponentName;
@@ -27,7 +30,7 @@ import android.net.Uri;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.util.Slog;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.SystemUIFactory;
@@ -47,7 +50,7 @@ import javax.inject.Inject;
*/
@SysUISingleton
public class ScreenshotSmartActions {
- private static final String TAG = "ScreenshotSmartActions";
+ private static final String TAG = logTag(ScreenshotSmartActions.class);
@Inject
public ScreenshotSmartActions() {}
@@ -57,18 +60,24 @@ public class ScreenshotSmartActions {
String screenshotId, Uri screenshotUri, Bitmap image,
ScreenshotNotificationSmartActionsProvider smartActionsProvider,
boolean smartActionsEnabled, UserHandle userHandle) {
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, String.format("getSmartActionsFuture id=%s, uri=%s, provider=%s, "
+ + "smartActionsEnabled=%b, userHandle=%s", screenshotId, screenshotUri,
+ smartActionsProvider.getClass(), smartActionsEnabled, userHandle));
+ }
if (!smartActionsEnabled) {
- Slog.i(TAG, "Screenshot Intelligence not enabled, returning empty list.");
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, "Screenshot Intelligence not enabled, returning empty list.");
+ }
return CompletableFuture.completedFuture(Collections.emptyList());
}
if (image.getConfig() != Bitmap.Config.HARDWARE) {
- Slog.w(TAG, String.format(
- "Bitmap expected: Hardware, Bitmap found: %s. Returning empty list.",
- image.getConfig()));
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, String.format("Bitmap expected: Hardware, Bitmap found: %s. "
+ + "Returning empty list.", image.getConfig()));
+ }
return CompletableFuture.completedFuture(Collections.emptyList());
}
-
- Slog.d(TAG, "Screenshot from user profile: " + userHandle.getIdentifier());
CompletableFuture<List<Notification.Action>> smartActionsFuture;
long startTimeMs = SystemClock.uptimeMillis();
try {
@@ -83,7 +92,9 @@ public class ScreenshotSmartActions {
} catch (Throwable e) {
long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
smartActionsFuture = CompletableFuture.completedFuture(Collections.emptyList());
- Slog.e(TAG, "Failed to get future for screenshot notification smart actions.", e);
+ if (DEBUG_ACTIONS) {
+ Log.e(TAG, "Failed to get future for screenshot notification smart actions.", e);
+ }
notifyScreenshotOp(screenshotId, smartActionsProvider,
ScreenshotNotificationSmartActionsProvider.ScreenshotOp.REQUEST_SMART_ACTIONS,
ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR,
@@ -97,12 +108,18 @@ public class ScreenshotSmartActions {
CompletableFuture<List<Notification.Action>> smartActionsFuture, int timeoutMs,
ScreenshotNotificationSmartActionsProvider smartActionsProvider) {
long startTimeMs = SystemClock.uptimeMillis();
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, String.format("getSmartActions id=%s, timeoutMs=%d, provider=%s",
+ screenshotId, timeoutMs, smartActionsProvider.getClass()));
+ }
try {
List<Notification.Action> actions = smartActionsFuture.get(timeoutMs,
TimeUnit.MILLISECONDS);
long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
- Slog.d(TAG, String.format("Got %d smart actions. Wait time: %d ms",
- actions.size(), waitTimeMs));
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, String.format("Got %d smart actions. Wait time: %d ms",
+ actions.size(), waitTimeMs));
+ }
notifyScreenshotOp(screenshotId, smartActionsProvider,
ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS,
ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.SUCCESS,
@@ -110,8 +127,10 @@ public class ScreenshotSmartActions {
return actions;
} catch (Throwable e) {
long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
- Slog.e(TAG, String.format("Error getting smart actions. Wait time: %d ms", waitTimeMs),
- e);
+ if (DEBUG_ACTIONS) {
+ Log.e(TAG, String.format("Error getting smart actions. Wait time: %d ms",
+ waitTimeMs), e);
+ }
ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status =
(e instanceof TimeoutException)
? ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.TIMEOUT
@@ -127,10 +146,14 @@ public class ScreenshotSmartActions {
ScreenshotNotificationSmartActionsProvider smartActionsProvider,
ScreenshotNotificationSmartActionsProvider.ScreenshotOp op,
ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status, long durationMs) {
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, String.format("%s notifyOp: %s id=%s, status=%s, durationMs=%d",
+ smartActionsProvider.getClass(), op, screenshotId, status, durationMs));
+ }
try {
smartActionsProvider.notifyOp(screenshotId, op, status, durationMs);
} catch (Throwable e) {
- Slog.e(TAG, "Error in notifyScreenshotOp: ", e);
+ Log.e(TAG, "Error in notifyScreenshotOp: ", e);
}
}
@@ -140,9 +163,13 @@ public class ScreenshotSmartActions {
ScreenshotNotificationSmartActionsProvider provider =
SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider(
context, THREAD_POOL_EXECUTOR, new Handler());
+ if (DEBUG_ACTIONS) {
+ Log.e(TAG, String.format("%s notifyAction: %s id=%s, isSmartAction=%b",
+ provider.getClass(), action, screenshotId, isSmartAction));
+ }
provider.notifyAction(screenshotId, action, isSmartAction);
} catch (Throwable e) {
- Slog.e(TAG, "Error in notifyScreenshotAction: ", e);
+ Log.e(TAG, "Error in notifyScreenshotAction: ", e);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 3814bd2999e9..cce60f9c7c9d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -18,6 +18,14 @@ package com.android.systemui.screenshot;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_SCROLL;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_UI;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW;
+import static com.android.systemui.screenshot.LogConfig.logTag;
+
import static java.util.Objects.requireNonNull;
import android.animation.Animator;
@@ -75,7 +83,7 @@ import java.util.function.Consumer;
public class ScreenshotView extends FrameLayout implements
ViewTreeObserver.OnComputeInternalInsetsListener {
- private static final String TAG = "ScreenshotView";
+ private static final String TAG = logTag(ScreenshotView.class);
private static final long SCREENSHOT_FLASH_IN_DURATION_MS = 133;
private static final long SCREENSHOT_FLASH_OUT_DURATION_MS = 217;
@@ -166,12 +174,18 @@ public class ScreenshotView extends FrameLayout implements
* @param onClick the action to take when the chip is clicked.
*/
public void showScrollChip(Runnable onClick) {
+ if (DEBUG_SCROLL) {
+ Log.d(TAG, "Showing Scroll option");
+ }
mScrollChip.setVisibility(VISIBLE);
- mScrollChip.setOnClickListener((v) ->
- onClick.run()
- // TODO Logging, store event consumer to a field
- //onElementTapped.accept(ScreenshotEvent.SCREENSHOT_SCROLL_TAPPED);
- );
+ mScrollChip.setOnClickListener((v) -> {
+ if (DEBUG_INPUT) {
+ Log.d(TAG, "scroll chip tapped");
+ }
+ onClick.run();
+ // TODO Logging, store event consumer to a field
+ //onElementTapped.accept(ScreenshotEvent.SCREENSHOT_SCROLL_TAPPED);
+ });
}
@Override // ViewTreeObserver.OnComputeInternalInsetsListener
@@ -179,15 +193,13 @@ public class ScreenshotView extends FrameLayout implements
inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
Region touchRegion = new Region();
- Rect screenshotRect = new Rect();
- mScreenshotPreview.getBoundsOnScreen(screenshotRect);
- touchRegion.op(screenshotRect, Region.Op.UNION);
- Rect actionsRect = new Rect();
- mActionsContainer.getBoundsOnScreen(actionsRect);
- touchRegion.op(actionsRect, Region.Op.UNION);
- Rect dismissRect = new Rect();
- mDismissButton.getBoundsOnScreen(dismissRect);
- touchRegion.op(dismissRect, Region.Op.UNION);
+ final Rect tmpRect = new Rect();
+ mScreenshotPreview.getBoundsOnScreen(tmpRect);
+ touchRegion.op(tmpRect, Region.Op.UNION);
+ mActionsContainer.getBoundsOnScreen(tmpRect);
+ touchRegion.op(tmpRect, Region.Op.UNION);
+ mDismissButton.getBoundsOnScreen(tmpRect);
+ touchRegion.op(tmpRect, Region.Op.UNION);
if (QuickStepContract.isGesturalMode(mNavMode)) {
// Receive touches in gesture insets such that they don't cause TOUCH_OUTSIDE
@@ -362,7 +374,6 @@ public class ScreenshotView extends FrameLayout implements
toCorner.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
mScreenshotPreview.setVisibility(View.VISIBLE);
}
});
@@ -380,8 +391,13 @@ public class ScreenshotView extends FrameLayout implements
dropInAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
+ if (DEBUG_ANIM) {
+ Log.d(TAG, "drop-in animation completed");
+ }
mDismissButton.setOnClickListener(view -> {
+ if (DEBUG_INPUT) {
+ Log.d(TAG, "dismiss button clicked");
+ }
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL);
animateDismissal();
});
@@ -497,7 +513,7 @@ public class ScreenshotView extends FrameLayout implements
try {
imageData.editAction.actionIntent.send();
} catch (PendingIntent.CanceledException e) {
- Log.e(TAG, "Intent cancelled", e);
+ Log.e(TAG, "PendingIntent was cancelled", e);
}
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED);
animateDismissal();
@@ -543,6 +559,9 @@ public class ScreenshotView extends FrameLayout implements
}
private void animateDismissal(Animator dismissAnimation) {
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "removing OnComputeInternalInsetsListener");
+ }
getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
mDismissAnimation = dismissAnimation;
mDismissAnimation.addListener(new AnimatorListenerAdapter() {
@@ -551,6 +570,9 @@ public class ScreenshotView extends FrameLayout implements
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
+ if (DEBUG_ANIM) {
+ Log.d(TAG, "Cancelled dismiss animation");
+ }
mCancelled = true;
}
@@ -558,17 +580,33 @@ public class ScreenshotView extends FrameLayout implements
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (!mCancelled) {
+ if (DEBUG_ANIM) {
+ Log.d(TAG, "after dismiss animation, calling onDismissRunnable.run()");
+ }
mOnDismissRunnable.run();
}
}
});
+ if (DEBUG_ANIM) {
+ Log.d(TAG, "Starting dismiss animation");
+ }
mDismissAnimation.start();
}
void reset() {
+ if (DEBUG_UI) {
+ Log.d(TAG, "reset screenshot view");
+ }
+
if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
+ if (DEBUG_ANIM) {
+ Log.d(TAG, "cancelling dismiss animation");
+ }
mDismissAnimation.cancel();
}
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "removing OnComputeInternalInsetsListener");
+ }
// Make sure we clean up the view tree observer
getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
// Clear any references to the bitmap
@@ -637,10 +675,9 @@ public class ScreenshotView extends FrameLayout implements
BitmapDrawable bitmapDrawable = new BitmapDrawable(res, bitmap);
if (insettedHeight == 0 || insettedWidth == 0 || bitmap.getWidth() == 0
|| bitmap.getHeight() == 0) {
- Log.e(TAG, String.format(
- "Can't create insetted drawable, using 0 insets "
- + "bitmap and insets create degenerate region: %dx%d %s",
- bitmap.getWidth(), bitmap.getHeight(), insets));
+ Log.e(TAG, "Can't create inset drawable, using 0 insets bitmap and insets create "
+ + "degenerate region: " + bitmap.getWidth() + "x" + bitmap.getHeight() + " "
+ + bitmapDrawable);
return bitmapDrawable;
}
@@ -689,12 +726,18 @@ public class ScreenshotView extends FrameLayout implements
} else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
if (isPastDismissThreshold()
&& (mDismissAnimation == null || !mDismissAnimation.isRunning())) {
+ if (DEBUG_INPUT) {
+ Log.d(TAG, "dismiss triggered via swipe gesture");
+ }
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED);
animateDismissal(createSwipeDismissAnimation());
return true;
} else if (MathUtils.dist(mStartX, mStartY, event.getRawX(), event.getRawY())
> dpToPx(CLICK_MOVEMENT_THRESHOLD_DP)) {
// if we've moved a non-negligible distance (but not past the threshold),
+ if (DEBUG_DISMISS) {
+ Log.d(TAG, "swipe gesture abandoned");
+ }
// start the return animation
if ((mDismissAnimation == null || !mDismissAnimation.isRunning())) {
createSwipeReturnAnimation().start();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
index ea835fa94fe8..e159992bc9a5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -16,6 +16,8 @@
package com.android.systemui.screenshot;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_SCROLL;
+
import static java.util.Objects.requireNonNull;
import android.annotation.UiContext;
@@ -49,10 +51,7 @@ public class ScrollCaptureClient {
@VisibleForTesting
static final int MATCH_ANY_TASK = ActivityTaskManager.INVALID_TASK_ID;
- private static final String TAG = "ScrollCaptureClient";
-
- /** Whether to log method names and arguments for most calls */
- private static final boolean DEBUG_TRACE = false;
+ private static final String TAG = LogConfig.logTag(ScrollCaptureClient.class);
/**
* A connection to a remote window. Starts a capture session.
@@ -155,7 +154,7 @@ public class ScrollCaptureClient {
*/
public void request(int displayId, int taskId, Consumer<Connection> consumer) {
try {
- if (DEBUG_TRACE) {
+ if (DEBUG_SCROLL) {
Log.d(TAG, "requestScrollCapture(displayId=" + displayId + ", " + mHostWindowToken
+ ", taskId=" + taskId + ", consumer=" + consumer + ")");
}
@@ -189,7 +188,7 @@ public class ScrollCaptureClient {
@Override
public void onConnected(IScrollCaptureConnection connection, Rect scrollBounds,
Point positionInWindow) throws RemoteException {
- if (DEBUG_TRACE) {
+ if (DEBUG_SCROLL) {
Log.d(TAG, "onConnected(connection=" + connection + ", scrollBounds=" + scrollBounds
+ ", positionInWindow=" + positionInWindow + ")");
}
@@ -202,7 +201,7 @@ public class ScrollCaptureClient {
@Override
public void onUnavailable() throws RemoteException {
- if (DEBUG_TRACE) {
+ if (DEBUG_SCROLL) {
Log.d(TAG, "onUnavailable");
}
// The targeted app does not support scroll capture
@@ -211,7 +210,7 @@ public class ScrollCaptureClient {
@Override
public void onCaptureStarted() {
- if (DEBUG_TRACE) {
+ if (DEBUG_SCROLL) {
Log.d(TAG, "onCaptureStarted()");
}
mSessionConsumer.accept(this);
@@ -224,7 +223,7 @@ public class ScrollCaptureClient {
if (frameNumber != ScrollCaptureViewSupport.NO_FRAME_PRODUCED) {
image = mReader.acquireNextImage();
}
- if (DEBUG_TRACE) {
+ if (DEBUG_SCROLL) {
Log.d(TAG, "onCaptureBufferSent(frameNumber=" + frameNumber
+ ", contentArea=" + contentArea + ") image=" + image);
}
@@ -237,7 +236,7 @@ public class ScrollCaptureClient {
@Override
public void onConnectionClosed() {
- if (DEBUG_TRACE) {
+ if (DEBUG_SCROLL) {
Log.d(TAG, "onConnectionClosed()");
}
disconnect();
@@ -261,7 +260,7 @@ public class ScrollCaptureClient {
// -> Error handling: BiConsumer<Session, Throwable> ?
@Override
public void start(int maxBufferCount, Consumer<Session> sessionConsumer) {
- if (DEBUG_TRACE) {
+ if (DEBUG_SCROLL) {
Log.d(TAG, "start(maxBufferCount=" + maxBufferCount
+ ", sessionConsumer=" + sessionConsumer + ")");
}
@@ -288,7 +287,7 @@ public class ScrollCaptureClient {
@Override
public void end(Runnable listener) {
- if (DEBUG_TRACE) {
+ if (DEBUG_SCROLL) {
Log.d(TAG, "end(listener=" + listener + ")");
}
if (mStarted) {
@@ -319,7 +318,7 @@ public class ScrollCaptureClient {
@Override
public void requestTile(Rect contentRect, Consumer<CaptureResult> consumer) {
- if (DEBUG_TRACE) {
+ if (DEBUG_SCROLL) {
Log.d(TAG, "requestTile(contentRect=" + contentRect + "consumer=" + consumer + ")");
}
mRequestRect = new Rect(contentRect);
@@ -337,7 +336,7 @@ public class ScrollCaptureClient {
*/
@Override
public void binderDied() {
- if (DEBUG_TRACE) {
+ if (DEBUG_SCROLL) {
Log.d(TAG, "binderDied()");
}
disconnect();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
index f32529fdaf04..3ad922b57c7c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
@@ -16,6 +16,7 @@
package com.android.systemui.screenshot;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_TYPE;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ID;
@@ -26,7 +27,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
-import android.util.Slog;
import javax.inject.Inject;
@@ -48,7 +48,9 @@ public class SmartActionsReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE);
- Slog.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent());
+ if (DEBUG_ACTIONS) {
+ Log.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent());
+ }
ActivityOptions opts = ActivityOptions.makeBasic();
try {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 2c82bcb24ad0..c2b20d37f3f3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -20,6 +20,10 @@ import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_COMPLETE;
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_SERVICE;
+import static com.android.systemui.screenshot.LogConfig.logTag;
import android.app.Service;
import android.content.BroadcastReceiver;
@@ -41,6 +45,8 @@ import android.os.UserManager;
import android.util.Log;
import android.view.WindowManager;
+import androidx.annotation.NonNull;
+
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.R;
@@ -51,89 +57,34 @@ import java.util.function.Consumer;
import javax.inject.Inject;
public class TakeScreenshotService extends Service {
- private static final String TAG = "TakeScreenshotService";
+ private static final String TAG = logTag(TakeScreenshotService.class);
private final ScreenshotController mScreenshot;
private final UserManager mUserManager;
private final UiEventLogger mUiEventLogger;
private final ScreenshotNotificationsController mNotificationsController;
+ private final Handler mHandler;
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-
+ private final BroadcastReceiver mCloseSystemDialogs = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction()) && mScreenshot != null) {
- mScreenshot.dismissScreenshot(false);
- }
- }
- };
-
- private Handler mHandler = new Handler(Looper.myLooper()) {
- @Override
- public void handleMessage(Message msg) {
- final Messenger callback = msg.replyTo;
- Consumer<Uri> uriConsumer = uri -> {
- Message reply = Message.obtain(null, SCREENSHOT_MSG_URI, uri);
- try {
- callback.send(reply);
- } catch (RemoteException e) {
- }
- };
- Runnable onComplete = () -> {
- Message reply = Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE);
- try {
- callback.send(reply);
- } catch (RemoteException e) {
+ if (DEBUG_DISMISS) {
+ Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
}
- };
-
- // If the storage for this user is locked, we have no place to store
- // the screenshot, so skip taking it instead of showing a misleading
- // animation and error notification.
- if (!mUserManager.isUserUnlocked()) {
- Log.w(TAG, "Skipping screenshot because storage is locked!");
- mNotificationsController.notifyScreenshotError(
- R.string.screenshot_failed_to_save_user_locked_text);
- post(() -> uriConsumer.accept(null));
- post(onComplete);
- return;
- }
-
- ScreenshotHelper.ScreenshotRequest screenshotRequest =
- (ScreenshotHelper.ScreenshotRequest) msg.obj;
-
- mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()));
-
- switch (msg.what) {
- case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
- mScreenshot.takeScreenshotFullscreen(uriConsumer, onComplete);
- break;
- case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
- mScreenshot.takeScreenshotPartial(uriConsumer, onComplete);
- break;
- case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
- Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
- screenshotRequest.getBitmapBundle());
- Rect screenBounds = screenshotRequest.getBoundsInScreen();
- Insets insets = screenshotRequest.getInsets();
- int taskId = screenshotRequest.getTaskId();
- int userId = screenshotRequest.getUserId();
- ComponentName topComponent = screenshotRequest.getTopComponent();
- mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
- taskId, userId, topComponent, uriConsumer, onComplete);
- break;
- default:
- Log.d(TAG, "Invalid screenshot option: " + msg.what);
+ mScreenshot.dismissScreenshot(false);
}
}
};
@Inject
- public TakeScreenshotService(
- ScreenshotController screenshotController,
- UserManager userManager,
+ public TakeScreenshotService(ScreenshotController screenshotController, UserManager userManager,
UiEventLogger uiEventLogger,
ScreenshotNotificationsController notificationsController) {
+ if (DEBUG_SERVICE) {
+ Log.d(TAG, "new " + this);
+ }
+ mHandler = new Handler(Looper.getMainLooper(), this::handleMessage);
mScreenshot = screenshotController;
mUserManager = userManager;
mUiEventLogger = uiEventLogger;
@@ -141,21 +92,124 @@ public class TakeScreenshotService extends Service {
}
@Override
- public IBinder onBind(Intent intent) {
- // register broadcast receiver
- IntentFilter filter = new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS);
- registerReceiver(mBroadcastReceiver, filter);
-
- return new Messenger(mHandler).getBinder();
+ public void onCreate() {
+ if (DEBUG_SERVICE) {
+ Log.d(TAG, "onCreate()");
+ }
+ }
+ @Override
+ public IBinder onBind(@NonNull Intent intent) {
+ registerReceiver(mCloseSystemDialogs, new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS));
+ final Messenger m = new Messenger(mHandler);
+ if (DEBUG_SERVICE) {
+ Log.d(TAG, "onBind: returning connection: " + m);
+ }
+ return m.getBinder();
}
@Override
public boolean onUnbind(Intent intent) {
+ if (DEBUG_SERVICE) {
+ Log.d(TAG, "onUnbind");
+ }
if (mScreenshot != null) {
mScreenshot.dismissScreenshot(true);
}
- unregisterReceiver(mBroadcastReceiver);
+ unregisterReceiver(mCloseSystemDialogs);
+ return false;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (DEBUG_SERVICE) {
+ Log.d(TAG, "onDestroy");
+ }
+ }
+
+ /** Respond to incoming Message via Binder (Messenger) */
+ private boolean handleMessage(Message msg) {
+ final Messenger replyTo = msg.replyTo;
+ final Runnable onComplete = () -> sendComplete(replyTo);
+ final Consumer<Uri> uriConsumer = (uri) -> reportUri(replyTo, uri);
+
+ // If the storage for this user is locked, we have no place to store
+ // the screenshot, so skip taking it instead of showing a misleading
+ // animation and error notification.
+ if (!mUserManager.isUserUnlocked()) {
+ Log.w(TAG, "Skipping screenshot because storage is locked!");
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_save_user_locked_text);
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "handleMessage: calling uriConsumer.accept(null)");
+ }
+ uriConsumer.accept(null);
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "handleMessage: calling onComplete.run()");
+ }
+ onComplete.run();
+ return true;
+ }
+
+ ScreenshotHelper.ScreenshotRequest screenshotRequest =
+ (ScreenshotHelper.ScreenshotRequest) msg.obj;
+
+ mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()));
+
+ switch (msg.what) {
+ case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
+ if (DEBUG_SERVICE) {
+ Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_FULLSCREEN");
+ }
+ mScreenshot.takeScreenshotFullscreen(uriConsumer, onComplete);
+ break;
+ case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
+ if (DEBUG_SERVICE) {
+ Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_SELECTED_REGION");
+ }
+ mScreenshot.takeScreenshotPartial(uriConsumer, onComplete);
+ break;
+ case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
+ if (DEBUG_SERVICE) {
+ Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE");
+ }
+ Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
+ screenshotRequest.getBitmapBundle());
+ Rect screenBounds = screenshotRequest.getBoundsInScreen();
+ Insets insets = screenshotRequest.getInsets();
+ int taskId = screenshotRequest.getTaskId();
+ int userId = screenshotRequest.getUserId();
+ ComponentName topComponent = screenshotRequest.getTopComponent();
+ mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
+ taskId, userId, topComponent, uriConsumer, onComplete);
+ break;
+ default:
+ Log.w(TAG, "Invalid screenshot option: " + msg.what);
+ return false;
+ }
return true;
+ };
+
+ private void sendComplete(Messenger target) {
+ try {
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "sendComplete: " + target);
+ }
+ target.send(Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE));
+ } catch (RemoteException e) {
+ Log.d(TAG, "ignored remote exception", e);
+ }
+ }
+
+ private void reportUri(Messenger target, Uri uri) {
+ try {
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "reportUri: " + target + " -> " + uri);
+ }
+ target.send(Message.obtain(null, SCREENSHOT_MSG_URI, uri));
+ } catch (RemoteException e) {
+ Log.d(TAG, "ignored remote exception", e);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index a252a7a12274..3765e5a26e8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -69,7 +69,6 @@ import com.android.systemui.util.wakelock.WakeLock;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.NumberFormat;
-import java.util.IllegalFormatConversionException;
import javax.inject.Inject;
@@ -575,24 +574,12 @@ public class KeyguardIndicationController implements StateListener,
String percentage = NumberFormat.getPercentInstance()
.format(mBatteryLevel / 100f);
if (hasChargingTime) {
- // We now have battery percentage in these strings and it's expected that all
- // locales will also have it in the future. For now, we still have to support the old
- // format until all languages get the new translations.
String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
mContext, mChargingTimeRemaining);
- try {
- return mContext.getResources().getString(chargingId, chargingTimeFormatted,
- percentage);
- } catch (IllegalFormatConversionException e) {
- return mContext.getResources().getString(chargingId, chargingTimeFormatted);
- }
+ return mContext.getResources().getString(chargingId, chargingTimeFormatted,
+ percentage);
} else {
- // Same as above
- try {
- return mContext.getResources().getString(chargingId, percentage);
- } catch (IllegalFormatConversionException e) {
- return mContext.getResources().getString(chargingId);
- }
+ return mContext.getResources().getString(chargingId, percentage);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
index db5458664023..2586e9403e01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -29,7 +29,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.palette.graphics.Palette;
import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.R;
+import com.android.settingslib.Utils;
import java.util.List;
@@ -143,7 +143,8 @@ public class MediaNotificationProcessor {
int foregroundColor = selectForegroundColor(backgroundColor, palette);
builder.setColorPalette(backgroundColor, foregroundColor);
} else {
- backgroundColor = mContext.getColor(R.color.notification_material_background_color);
+ backgroundColor = Utils.getColorAttr(mContext, android.R.attr.colorBackground)
+ .getDefaultColor();
}
Bitmap colorized = mColorizer.colorize(drawable, backgroundColor,
mContext.getResources().getConfiguration().getLayoutDirection() ==
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 10273cbbebad..86ebc6b2c4ce 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
@@ -34,6 +34,7 @@ import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import com.android.internal.jank.InteractionJankMonitor;
+import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -169,13 +170,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
private void updateColors() {
- mNormalColor = mContext.getColor(R.color.notification_material_background_color);
+ mNormalColor = Utils.getColorAttr(mContext, android.R.attr.colorBackground)
+ .getDefaultColor();
mTintedRippleColor = mContext.getColor(
R.color.notification_ripple_tinted_color);
mNormalRippleColor = mContext.getColor(
R.color.notification_ripple_untinted_color);
mDimmedAlpha = Color.alpha(mContext.getColor(
- R.color.notification_material_background_dimmed_color));
+ R.color.notification_background_dimmed_color));
}
private void initDimens() {
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 7071b73c2ebf..8ac5b933e4f9 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
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.row;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -35,7 +34,6 @@ import android.widget.FrameLayout;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -168,9 +166,6 @@ public class NotificationGuts extends FrameLayout {
}
}
};
- final TypedArray ta = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.Theme, 0, 0);
- ta.recycle();
}
public NotificationGuts(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 6920e3f4a7c6..416c5af93400 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
+import com.android.settingslib.Utils;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.notification.TransformState;
@@ -324,8 +325,8 @@ public abstract class NotificationViewWrapper implements TransformableView {
if (customBackgroundColor != 0) {
return customBackgroundColor;
}
- return mView.getContext().getColor(
- com.android.internal.R.color.notification_material_background_color);
+ return Utils.getColorAttr(mView.getContext(), android.R.attr.colorBackground)
+ .getDefaultColor();
}
public void setLegacy(boolean legacy) {
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 ba5f95e9c4d8..5cc17a08504f 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
@@ -50,7 +50,6 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.MathUtils;
import android.util.Pair;
-import android.view.ContextThemeWrapper;
import android.view.DisplayCutout;
import android.view.InputDevice;
import android.view.LayoutInflater;
@@ -385,7 +384,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
*/
private float mBackgroundXFactor = 1f;
- private boolean mUsingLightTheme;
private boolean mQsExpanded;
private boolean mForwardScrollable;
private boolean mBackwardScrollable;
@@ -4122,15 +4120,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* @param lightTheme True if light theme should be used.
*/
@ShadeViewRefactor(RefactorComponent.DECORATOR)
- void updateDecorViews(boolean lightTheme) {
- if (lightTheme == mUsingLightTheme) {
- return;
- }
- mUsingLightTheme = lightTheme;
- Context context = new ContextThemeWrapper(mContext,
- lightTheme ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI);
+ void updateDecorViews() {
final @ColorInt int textColor =
- Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor);
+ Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
mSectionsManager.setHeaderForegroundColor(textColor);
mFooterView.setTextColor(textColor);
mEmptyShadeView.setTextColor(textColor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index abbbbb8352f5..8a0330912502 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -162,7 +162,6 @@ public class NotificationStackScrollLayoutController {
private final KeyguardMediaController mKeyguardMediaController;
private final SysuiStatusBarStateController mStatusBarStateController;
private final KeyguardBypassController mKeyguardBypassController;
- private final SysuiColorExtractor mColorExtractor;
private final NotificationLockscreenUserManager mLockscreenUserManager;
// TODO: StatusBar should be encapsulated behind a Controller
private final StatusBar mStatusBar;
@@ -224,12 +223,14 @@ public class NotificationStackScrollLayoutController {
public void onOverlayChanged() {
updateShowEmptyShadeView();
mView.updateCornerRadius();
+ mView.updateBgColor();
mView.reinflateViews();
}
@Override
public void onUiModeChanged() {
mView.updateBgColor();
+ mView.updateDecorViews();
}
@Override
@@ -577,7 +578,6 @@ public class NotificationStackScrollLayoutController {
mKeyguardMediaController = keyguardMediaController;
mKeyguardBypassController = keyguardBypassController;
mZenModeController = zenModeController;
- mColorExtractor = colorExtractor;
mLockscreenUserManager = lockscreenUserManager;
mMetricsLogger = metricsLogger;
mFalsingCollector = falsingCollector;
@@ -689,12 +689,6 @@ public class NotificationStackScrollLayoutController {
Settings.Secure.NOTIFICATION_DISMISS_RTL,
Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
- mOnColorsChangedListener = (colorExtractor, which) -> {
- final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
- mView.updateDecorViews(useDarkText);
- };
- mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
-
mKeyguardMediaController.setVisibilityChangedListener(visible -> {
mView.setKeyguardMediaControllorVisible(visible);
if (visible) {
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 54fb863b5de7..0df3347b8f89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -49,7 +49,7 @@ public class LockIcon extends KeyguardAffordanceView {
static final int STATE_SCANNING_FACE = 2;
static final int STATE_BIOMETRICS_ERROR = 3;
private float mDozeAmount;
- private int mIconColor;
+ private int mIconColor = Color.TRANSPARENT;
private int mOldState;
private int mState;
private boolean mDozing;
@@ -149,7 +149,10 @@ public class LockIcon extends KeyguardAffordanceView {
updateDarkTint();
}
- void onThemeChange(int iconColor) {
+ void updateColor(int iconColor) {
+ if (mIconColor == iconColor) {
+ return;
+ }
mDrawableCache.clear();
mIconColor = iconColor;
updateDarkTint();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 289ff71dcb46..0e7e2fd8173c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -84,6 +84,7 @@ public class LockscreenLockIconController {
private boolean mDocked;
private boolean mWakeAndUnlockRunning;
private boolean mShowingLaunchAffordance;
+ private boolean mBouncerShowing;
private boolean mBouncerShowingScrimmed;
private boolean mFingerprintUnlock;
private int mStatusBarState = StatusBarState.SHADE;
@@ -142,16 +143,13 @@ public class LockscreenLockIconController {
private int mDensity;
@Override
- public void onThemeChanged() {
- if (mLockIcon == null) {
- return;
- }
+ public void onUiModeChanged() {
+ updateColor();
+ }
- TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
- null, new int[]{ R.attr.wallpaperTextColor }, 0, 0);
- int iconColor = typedArray.getColor(0, Color.WHITE);
- typedArray.recycle();
- mLockIcon.onThemeChange(iconColor);
+ @Override
+ public void onOverlayChanged() {
+ updateColor();
}
@Override
@@ -350,6 +348,7 @@ public class LockscreenLockIconController {
*/
public void attach(LockIcon lockIcon) {
mLockIcon = lockIcon;
+ updateColor();
mLockIcon.setOnClickListener(this::handleClick);
mLockIcon.setOnLongClickListener(this::handleLongClick);
@@ -408,11 +407,22 @@ public class LockscreenLockIconController {
}
/** Sets whether the bouncer is showing. */
- public void setBouncerShowingScrimmed(boolean bouncerShowing) {
- mBouncerShowingScrimmed = bouncerShowing;
- if (mKeyguardBypassController.getBypassEnabled()) {
- update();
+ public void setBouncerShowingScrimmed(boolean showing, boolean scrimmed) {
+ mBouncerShowing = showing;
+ mBouncerShowingScrimmed = scrimmed;
+ update();
+ }
+
+ private void updateColor() {
+ if (mLockIcon == null) {
+ return;
}
+
+ TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
+ null, new int[]{ android.R.attr.textColorPrimary }, 0, 0);
+ int iconColor = typedArray.getColor(0, Color.WHITE);
+ typedArray.recycle();
+ mLockIcon.updateColor(iconColor);
}
/**
@@ -510,7 +520,10 @@ public class LockscreenLockIconController {
return changed;
}
boolean onAodOrDocked = mStatusBarStateController.isDozing() || mDocked;
- boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance;
+ boolean onKeyguardWithoutBouncer = mStatusBarState == StatusBarState.KEYGUARD
+ && !mBouncerShowing;
+ boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance
+ || onKeyguardWithoutBouncer;
boolean fingerprintOrBypass = mFingerprintUnlock
|| mKeyguardBypassController.getBypassEnabled();
if (fingerprintOrBypass && !mBouncerShowingScrimmed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index c67e8fd4f89c..84eacdc41841 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -86,6 +86,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
@@ -140,6 +141,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import javax.inject.Inject;
+import javax.inject.Provider;
@StatusBarComponent.StatusBarScope
public class NotificationPanelViewController extends PanelViewController {
@@ -184,7 +186,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final MetricsLogger mMetricsLogger;
private final ActivityManager mActivityManager;
private final ConfigurationController mConfigurationController;
- private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
+ private final Provider<FlingAnimationUtils.Builder> mFlingAnimationUtilsBuilder;
private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
private final NotificationIconAreaController mNotificationIconAreaController;
@@ -304,7 +306,6 @@ public class NotificationPanelViewController extends PanelViewController {
private FrameLayout mQsFrame;
private KeyguardStatusViewController mKeyguardStatusViewController;
private DisabledUdfpsController mDisabledUdfpsController;
- private View mQsNavbarScrim;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
private boolean mAnimateNextPositionUpdate;
@@ -455,6 +456,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final CommandQueue mCommandQueue;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final ShadeController mShadeController;
+ private final MediaDataManager mMediaDataManager;
private int mDisplayId;
/**
@@ -535,7 +537,7 @@ public class NotificationPanelViewController extends PanelViewController {
KeyguardUpdateMonitor keyguardUpdateMonitor, MetricsLogger metricsLogger,
ActivityManager activityManager,
ConfigurationController configurationController,
- FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
+ Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
ConversationNotificationManager conversationNotificationManager,
MediaHierarchyManager mediaHierarchyManager,
@@ -546,10 +548,11 @@ public class NotificationPanelViewController extends PanelViewController {
NotificationGroupManagerLegacy groupManager,
NotificationIconAreaController notificationIconAreaController,
AuthController authController,
- QSDetailDisplayer qsDetailDisplayer) {
+ QSDetailDisplayer qsDetailDisplayer,
+ MediaDataManager mediaDataManager) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
- latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
+ latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager);
mView = view;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
@@ -576,6 +579,7 @@ public class NotificationPanelViewController extends PanelViewController {
mPulseExpansionHandler = pulseExpansionHandler;
mDozeParameters = dozeParameters;
mBiometricUnlockController = biometricUnlockController;
+ mMediaDataManager = mediaDataManager;
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
if (mQs != null) {
mQs.animateHeaderSlidingOut();
@@ -650,7 +654,6 @@ public class NotificationPanelViewController extends PanelViewController {
mOnEmptySpaceClickListener);
addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp);
mKeyguardBottomArea = mView.findViewById(R.id.keyguard_bottom_area);
- mQsNavbarScrim = mView.findViewById(R.id.qs_navbar_scrim);
mLastOrientation = mResources.getConfiguration().orientation;
initBottomArea();
@@ -688,7 +691,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected void loadDimens() {
super.loadDimens();
- mFlingAnimationUtils = mFlingAnimationUtilsBuilder.reset()
+ mFlingAnimationUtils = mFlingAnimationUtilsBuilder.get()
.setMaxLengthSeconds(0.4f).build();
mStatusBarMinHeight = mResources.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
@@ -892,7 +895,8 @@ public class NotificationPanelViewController extends PanelViewController {
int clockPreferredY = mKeyguardStatusViewController.getClockPreferredY(totalHeight);
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
final boolean hasVisibleNotifications = !bypassEnabled
- && mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0;
+ && (mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0
+ || mMediaDataManager.hasActiveMedia());
mKeyguardStatusViewController.setHasVisibleNotifications(hasVisibleNotifications);
mClockPositionAlgorithm.setup(mStatusBarMinHeight, totalHeight - bottomPadding,
mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
@@ -1730,9 +1734,6 @@ public class NotificationPanelViewController extends PanelViewController {
mBarState != KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
- mQsNavbarScrim.setVisibility(
- mBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling
- && mQsScrimEnabled ? View.VISIBLE : View.INVISIBLE);
if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
}
@@ -1757,10 +1758,6 @@ public class NotificationPanelViewController extends PanelViewController {
updateKeyguardBottomAreaAlpha();
updateBigClockAlpha();
}
- if (mBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling
- && mQsScrimEnabled) {
- mQsNavbarScrim.setAlpha(getQsExpansionFraction());
- }
if (mAccessibilityManager.isEnabled()) {
mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
@@ -2041,8 +2038,8 @@ public class NotificationPanelViewController extends PanelViewController {
maxHeight = calculatePanelHeightShade();
}
maxHeight = Math.max(min, maxHeight);
- if (maxHeight == 0) {
- Log.wtf(TAG, "maxPanelHeight is 0. getOverExpansionAmount(): "
+ if (maxHeight == 0 || isNaN(maxHeight)) {
+ Log.wtf(TAG, "maxPanelHeight is invalid. getOverExpansionAmount(): "
+ getOverExpansionAmount() + ", calculatePanelHeightQsExpanded: "
+ calculatePanelHeightQsExpanded() + ", calculatePanelHeightShade: "
+ calculatePanelHeightShade() + ", mStatusBarMinHeight = "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 4af27877c201..9e7efc12f4f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -37,22 +37,21 @@ import android.view.animation.Interpolator;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.function.TriConsumer;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.Utils;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -71,8 +70,7 @@ import javax.inject.Inject;
* security method gets shown).
*/
@SysUISingleton
-public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnColorsChangedListener,
- Dumpable {
+public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dumpable {
static final String TAG = "ScrimController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -125,12 +123,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
* The default scrim under the shade and dialogs.
* This should not be lower than 0.54, otherwise we won't pass GAR.
*/
- public static final float BUSY_SCRIM_ALPHA = 0.85f;
+ public static final float BUSY_SCRIM_ALPHA = 1f;
/**
* Same as above, but when blur is supported.
*/
- public static final float BLUR_SCRIM_ALPHA = 0.54f;
+ public static final float BLUR_SCRIM_ALPHA = 0.80f;
static final int TAG_KEY_ANIM = R.id.scrim;
private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
@@ -153,8 +151,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
private final AlarmTimeout mTimeTicker;
private final KeyguardVisibilityCallback mKeyguardVisibilityCallback;
private final Handler mHandler;
+ private final BlurUtils mBlurUtils;
- private final SysuiColorExtractor mColorExtractor;
private GradientColors mColors;
private boolean mNeedsDrawableColorUpdate;
@@ -204,12 +202,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
AlarmManager alarmManager, KeyguardStateController keyguardStateController,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
- KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor,
- DockManager dockManager, BlurUtils blurUtils) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
+ BlurUtils blurUtils, ConfigurationController configurationController) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = blurUtils.supportsBlursOnWindows()
? BLUR_SCRIM_ALPHA : BUSY_SCRIM_ALPHA;
+ mBlurUtils = blurUtils;
mKeyguardStateController = keyguardStateController;
mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
@@ -230,11 +229,24 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
keyguardStateController.getKeyguardFadingAwayDuration());
}
});
+ configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onThemeChanged() {
+ ScrimController.this.onThemeChanged();
+ }
- mColorExtractor = sysuiColorExtractor;
- mColorExtractor.addOnColorsChangedListener(this);
- mColors = mColorExtractor.getNeutralColors();
- mNeedsDrawableColorUpdate = true;
+ @Override
+ public void onOverlayChanged() {
+ ScrimController.this.onThemeChanged();
+ }
+
+ @Override
+ public void onUiModeChanged() {
+ ScrimController.this.onThemeChanged();
+ }
+ });
+
+ mColors = new GradientColors();
}
/**
@@ -245,6 +257,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
mScrimBehind = scrimBehind;
mScrimInFront = scrimInFront;
mScrimForBubble = scrimForBubble;
+ updateThemeColors();
if (mScrimBehindChangeRunnable != null) {
mScrimBehind.setChangeRunnable(mScrimBehindChangeRunnable);
@@ -619,11 +632,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
mScrimInFront.setColors(mColors, animateScrimInFront);
mScrimBehind.setColors(mColors, animateScrimBehind);
- // Calculate minimum scrim opacity for white or black text.
- int textColor = mColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
- int mainColor = mColors.getMainColor();
- float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
- 4.5f /* minimumContrast */) / 255f;
dispatchScrimState(mScrimBehind.getViewAlpha());
}
@@ -968,10 +976,19 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
// Don't care in the base class.
}
- @Override
- public void onColorsChanged(ColorExtractor colorExtractor, int which) {
- mColors = mColorExtractor.getNeutralColors();
+ private void updateThemeColors() {
+ int background = Utils.getColorAttr(mScrimBehind.getContext(),
+ android.R.attr.colorBackgroundFloating).getDefaultColor();
+ int accent = Utils.getColorAccent(mScrimBehind.getContext()).getDefaultColor();
+ mColors.setMainColor(background);
+ mColors.setSecondaryColor(accent);
+ mColors.setSupportsDarkText(
+ ColorUtils.calculateContrast(mColors.getMainColor(), Color.WHITE) > 4.5);
mNeedsDrawableColorUpdate = true;
+ }
+
+ private void onThemeChanged() {
+ updateThemeColors();
scheduleUpdate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c8c5a6331a3b..9e872ab65591 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3782,7 +3782,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mBouncerShowing = bouncerShowing;
mKeyguardBypassController.setBouncerShowing(bouncerShowing);
mPulseExpansionHandler.setBouncerShowing(bouncerShowing);
- mLockscreenLockIconController.setBouncerShowingScrimmed(isBouncerShowingScrimmed());
+ mLockscreenLockIconController.setBouncerShowingScrimmed(bouncerShowing,
+ isBouncerShowingScrimmed());
if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
updateHideIconsForBouncer(true /* animate */);
mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index 0aa2a739eb82..50cef781d9d0 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -47,7 +47,7 @@ import java.util.stream.Collectors;
*/
@SysUISingleton
public class ThemeOverlayApplier implements Dumpable {
- private static final String TAG = "ThemeOverlayManager";
+ private static final String TAG = "ThemeOverlayApplier";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index c4e2b5d47ba8..006ecb937922 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -307,13 +307,13 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
if (!hasSystemPalette && mSystemOverlayColor != Color.TRANSPARENT) {
categoryToPackage.put(OVERLAY_CATEGORY_SYSTEM_PALETTE,
ThemeOverlayApplier.MONET_SYSTEM_PALETTE_PACKAGE
- + Integer.toHexString(mSystemOverlayColor).toUpperCase());
+ + getColorString(mSystemOverlayColor));
}
// Same for the accent color
if (!hasAccentColor && mAccentOverlayColor != Color.TRANSPARENT) {
categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR,
ThemeOverlayApplier.MONET_ACCENT_COLOR_PACKAGE
- + Integer.toHexString(mAccentOverlayColor).toUpperCase());
+ + getColorString(mAccentOverlayColor));
}
Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser));
@@ -325,6 +325,14 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
mThemeManager.applyCurrentUserOverlays(categoryToPackage, userHandles);
}
+ private String getColorString(int color) {
+ String colorString = Integer.toHexString(color).toUpperCase();
+ while (colorString.length() < 6) {
+ colorString = "0" + colorString;
+ }
+ return colorString;
+ }
+
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("mLockColors=" + mLockColors);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index 86ba5f1f74a9..8dea5b5a19a3 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -22,6 +22,7 @@ import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
@@ -34,6 +35,7 @@ import com.android.wm.shell.pip.tv.PipController;
import com.android.wm.shell.pip.tv.PipControlsView;
import com.android.wm.shell.pip.tv.PipControlsViewController;
import com.android.wm.shell.pip.tv.PipNotification;
+import com.android.wm.shell.pip.tv.TvPipMenuController;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
@@ -44,7 +46,7 @@ import dagger.Provides;
/**
* Dagger module for TV Pip.
*/
-@Module
+@Module(includes = {WMShellBaseModule.class})
public abstract class TvPipModule {
@WMSingleton
@Provides
@@ -53,6 +55,7 @@ public abstract class TvPipModule {
PipBoundsState pipBoundsState,
PipBoundsAlgorithm pipBoundsAlgorithm,
PipTaskOrganizer pipTaskOrganizer,
+ TvPipMenuController tvPipMenuController,
PipMediaController pipMediaController,
PipNotification pipNotification,
TaskStackListenerImpl taskStackListener,
@@ -63,6 +66,7 @@ public abstract class TvPipModule {
pipBoundsState,
pipBoundsAlgorithm,
pipTaskOrganizer,
+ tvPipMenuController,
pipMediaController,
pipNotification,
taskStackListener,
@@ -104,14 +108,22 @@ public abstract class TvPipModule {
@WMSingleton
@Provides
+ static TvPipMenuController providesPipTvMenuController(Context context,
+ PipBoundsState pipBoundsState, SystemWindows systemWindows) {
+ return new TvPipMenuController(context, pipBoundsState, systemWindows);
+ }
+
+ @WMSingleton
+ @Provides
static PipTaskOrganizer providePipTaskOrganizer(Context context,
+ TvPipMenuController tvMenuController,
PipBoundsState pipBoundsState,
PipBoundsAlgorithm pipBoundsAlgorithm,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
- null /* menuActivityController */, pipSurfaceTransactionHelper, splitScreenOptional,
+ tvMenuController, pipSurfaceTransactionHelper, splitScreenOptional,
displayController, pipUiEventLogger, shellTaskOrganizer);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index f88bedd88d9f..06f1522a7256 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -41,7 +41,7 @@ import dagger.Provides;
* Provides dependencies from {@link com.android.wm.shell} which could be customized among different
* branches of SystemUI.
*/
-@Module(includes = {WMShellBaseModule.class, TvPipModule.class})
+@Module(includes = {TvPipModule.class})
public class TvWMShellModule {
@WMSingleton
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 7a1c05890873..5f48c4294524 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -41,9 +41,9 @@ import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.pip.phone.PipAppOpsListener;
import com.android.wm.shell.pip.phone.PipController;
-import com.android.wm.shell.pip.phone.PipMenuActivityController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -93,12 +93,12 @@ public class WMShellModule {
static Optional<Pip> providePip(Context context, DisplayController displayController,
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
- PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
+ PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
return Optional.ofNullable(PipController.create(context, displayController,
pipAppOpsListener, pipBoundsAlgorithm, pipBoundsState, pipMediaController,
- pipMenuActivityController, pipTaskOrganizer, pipTouchHandler,
+ phonePipMenuController, pipTaskOrganizer, pipTouchHandler,
windowManagerShellWrapper, taskStackListener, mainExecutor));
}
@@ -117,20 +117,20 @@ public class WMShellModule {
@WMSingleton
@Provides
- static PipMenuActivityController providesPipMenuActivityController(Context context,
+ static PhonePipMenuController providesPipPhoneMenuController(Context context,
PipMediaController pipMediaController, SystemWindows systemWindows) {
- return new PipMenuActivityController(context, pipMediaController, systemWindows);
+ return new PhonePipMenuController(context, pipMediaController, systemWindows);
}
@WMSingleton
@Provides
static PipTouchHandler providePipTouchHandler(Context context,
- PipMenuActivityController menuActivityController, PipBoundsAlgorithm pipBoundsAlgorithm,
+ PhonePipMenuController menuPhoneController, PipBoundsAlgorithm pipBoundsAlgorithm,
PipBoundsState pipBoundsState,
PipTaskOrganizer pipTaskOrganizer,
FloatingContentCoordinator floatingContentCoordinator,
PipUiEventLogger pipUiEventLogger) {
- return new PipTouchHandler(context, menuActivityController, pipBoundsAlgorithm,
+ return new PipTouchHandler(context, menuPhoneController, pipBoundsAlgorithm,
pipBoundsState, pipTaskOrganizer, floatingContentCoordinator, pipUiEventLogger);
}
@@ -139,12 +139,12 @@ public class WMShellModule {
static PipTaskOrganizer providePipTaskOrganizer(Context context,
PipBoundsState pipBoundsState,
PipBoundsAlgorithm pipBoundsAlgorithm,
- PipMenuActivityController menuActivityController,
+ PhonePipMenuController menuPhoneController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
- menuActivityController, pipSurfaceTransactionHelper, splitScreenOptional,
+ menuPhoneController, pipSurfaceTransactionHelper, splitScreenOptional,
displayController, pipUiEventLogger, shellTaskOrganizer);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index eef38d316775..b03dc94fde33 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -34,6 +34,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
@@ -80,6 +81,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
@Mock
private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController;
+ @Mock
+ private ConfigurationController mConfigurationController;
private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
@@ -92,8 +95,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
mKeyguardSecurityContainerController = new KeyguardSecurityContainerController.Factory(
mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
- mKeyguardStateController, mKeyguardSecurityViewFlipperController)
- .create(mSecurityCallback);
+ mKeyguardStateController, mKeyguardSecurityViewFlipperController,
+ mConfigurationController).create(mSecurityCallback);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
new file mode 100644
index 000000000000..19f0a15c8936
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier;
+
+import static com.android.systemui.util.mockito.KotlinMockitoHelpersKt.any;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.view.MotionEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManagerFake;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class BrightLineClassifierTest extends SysuiTestCase {
+ private BrightLineFalsingManager mBrightLineFalsingManager;
+ @Mock
+ private FalsingDataProvider mFalsingDataProvider;
+ private final DockManagerFake mDockManager = new DockManagerFake();
+ private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
+ private final Set<FalsingClassifier> mClassifiers = new HashSet<>();
+ @Mock
+ private SingleTapClassifier mSingleTapClassfier;
+ @Mock
+ private DoubleTapClassifier mDoubleTapClassifier;
+ @Mock
+ private FalsingClassifier mClassifierA;
+ @Mock
+ private FalsingClassifier mClassifierB;
+ private final List<MotionEvent> mMotionEventList = new ArrayList<>();
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mClassifiers.add(mClassifierA);
+ mClassifiers.add(mClassifierB);
+ when(mFalsingDataProvider.isDirty()).thenReturn(true);
+ when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
+ mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager,
+ mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier, false);
+ }
+
+ @Test
+ public void testRegisterSessionListener() {
+ verify(mFalsingDataProvider).addSessionListener(
+ any(FalsingDataProvider.SessionListener.class));
+
+ mBrightLineFalsingManager.cleanup();
+ verify(mFalsingDataProvider).removeSessionListener(
+ any(FalsingDataProvider.SessionListener.class));
+ }
+
+ @Test
+ public void testIsFalseTouch_NoClassifiers() {
+ mClassifiers.clear();
+
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseTouch_ClassffiersPass() {
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseTouch_ClassifierARejects() {
+ when(mClassifierA.isFalseTouch()).thenReturn(true);
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue();
+ }
+
+ @Test
+ public void testIsFalseTouch_ClassifierBRejects() {
+ when(mClassifierB.isFalseTouch()).thenReturn(true);
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue();
+ }
+
+ @Test
+ public void testIsFalseTouch_FaceAuth() {
+ // Even when the classifiers report a false, we should allow.
+ when(mClassifierA.isFalseTouch()).thenReturn(true);
+ when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
+
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseTouch_Docked() {
+ // Even when the classifiers report a false, we should allow.
+ when(mClassifierA.isFalseTouch()).thenReturn(true);
+ mDockManager.setIsDocked(true);
+
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseTap_BasicCheck() {
+ when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(false);
+
+ assertThat(mBrightLineFalsingManager.isFalseTap(false)).isTrue();
+
+ when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true);
+
+ assertThat(mBrightLineFalsingManager.isFalseTap(false)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseTap_RobustCheck_NoFaceAuth() {
+ when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true);
+ mFalsingDataProvider.setJustUnlockedWithFace(false);
+ assertThat(mBrightLineFalsingManager.isFalseTap(true)).isTrue();
+ }
+
+ @Test
+ public void testIsFalseTap_RobustCheck_FaceAuth() {
+ when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true);
+ when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
+ assertThat(mBrightLineFalsingManager.isFalseTap(true)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseDoubleTap() {
+ when(mDoubleTapClassifier.isFalseTouch()).thenReturn(false);
+
+ assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isFalse();
+
+ when(mDoubleTapClassifier.isFalseTouch()).thenReturn(true);
+
+ assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java
index 714d6581ff00..7659db8cc9ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
@@ -27,8 +27,6 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
index d66c7a9d43a5..013fa369e876 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -23,8 +23,6 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
index 288ab0ad6596..4c4108a0cb90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -27,9 +27,6 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java
index b512f0d6ef32..ee289b5b922d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -26,8 +26,6 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java
index c2e290f166a3..38b025f675ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.GENERIC;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -28,8 +28,6 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxyFake;
import com.android.systemui.util.sensors.ProximitySensor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
index d67f2b833deb..941e12e475f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -25,9 +25,6 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBufferTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java
index 1dfffb271f02..6e312594a2e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBufferTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
index 5f3b84c2f7ae..6b9bb4fedd16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
@@ -33,9 +33,6 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
index e49262f5099f..339dd9e9e6d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -23,7 +23,6 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
index a6355880c660..37540621557f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
@@ -22,6 +22,7 @@ package com.android.systemui.dock;
public class DockManagerFake implements DockManager {
DockEventListener mCallback;
AlignmentStateListener mAlignmentListener;
+ private boolean mDocked;
@Override
public void addListener(DockEventListener callback) {
@@ -45,7 +46,11 @@ public class DockManagerFake implements DockManager {
@Override
public boolean isDocked() {
- return false;
+ return mDocked;
+ }
+
+ public void setIsDocked(boolean docked) {
+ mDocked = docked;
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 3d582e74ea4e..d4a94a19af4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -63,6 +63,7 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.statusbar.CommandQueue;
@@ -197,6 +198,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@Mock
private AuthController mAuthController;
+ @Mock
+ private MediaDataManager mMediaDataManager;
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
@@ -267,7 +270,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
mMetricsLogger, mActivityManager, mConfigurationController,
- flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
+ () -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
mBiometricUnlockController, mStatusBarKeyguardViewManager,
mNotificationStackScrollLayoutController,
@@ -275,7 +278,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mGroupManager,
mNotificationAreaController,
mAuthController,
- new QSDetailDisplayer());
+ new QSDetailDisplayer(),
+ mMediaDataManager);
mNotificationPanelViewController.initDependencies(
mStatusBar,
mNotificationShelfController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 23f263746fb3..eaf31ed17bb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -48,10 +48,10 @@ import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.wakelock.DelayedWakeLock;
import com.android.systemui.utils.os.FakeHandler;
@@ -99,11 +99,11 @@ public class ScrimControllerTest extends SysuiTestCase {
@Mock
KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
- private SysuiColorExtractor mSysuiColorExtractor;
- @Mock
private DockManager mDockManager;
@Mock
private BlurUtils mBlurUtils;
+ @Mock
+ private ConfigurationController mConfigurationController;
private static class AnimatorListener implements Animator.AnimatorListener {
@@ -196,6 +196,7 @@ public class ScrimControllerTest extends SysuiTestCase {
when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true);
+ when(mBlurUtils.supportsBlursOnWindows()).thenReturn(true);
doAnswer((Answer<Void>) invocation -> {
mScrimState = invocation.getArgument(0);
@@ -211,14 +212,12 @@ public class ScrimControllerTest extends SysuiTestCase {
.thenReturn(mDelayedWakeLockBuilder);
when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock);
- when(mSysuiColorExtractor.getNeutralColors()).thenReturn(new GradientColors());
-
when(mDockManager.isDocked()).thenReturn(false);
mScrimController = new ScrimController(mLightBarController,
mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
- new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mSysuiColorExtractor,
- mDockManager, mBlurUtils);
+ new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
+ mDockManager, mBlurUtils, mConfigurationController);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mScrimInFront, mScrimForBubble);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -520,10 +519,10 @@ public class ScrimControllerTest extends SysuiTestCase {
Assert.assertEquals(ScrimController.TRANSPARENT,
mScrimInFront.getViewAlpha(), 0.0f);
// Back scrim should be visible
- Assert.assertEquals(ScrimController.BUSY_SCRIM_ALPHA,
+ Assert.assertEquals(ScrimController.BLUR_SCRIM_ALPHA,
mScrimBehind.getViewAlpha(), 0.0f);
// Bubble scrim should be visible
- Assert.assertEquals(ScrimController.BUSY_SCRIM_ALPHA,
+ Assert.assertEquals(ScrimController.BLUR_SCRIM_ALPHA,
mScrimBehind.getViewAlpha(), 0.0f);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index aee884022d95..c826cbcb5389 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -107,7 +107,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
eq(UserHandle.USER_ALL));
verify(mDumpManager).registerDumpable(any(), any());
- List<Integer> colorList = List.of(Color.RED, Color.BLUE);
+ List<Integer> colorList = List.of(Color.RED, Color.BLUE, 0x0CCCCC, 0x000111);
when(mThemeOverlayApplier.getAvailableAccentColors()).thenReturn(colorList);
when(mThemeOverlayApplier.getAvailableSystemColors()).thenReturn(colorList);
}
@@ -148,6 +148,23 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
}
@Test
+ public void onWallpaperColorsChanged_addsLeadingZerosToColors() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(0x0CCCCC),
+ Color.valueOf(0x000111), null);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ ArgumentCaptor<Map<String, String>> themeOverlays = ArgumentCaptor.forClass(Map.class);
+
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(themeOverlays.capture(), any());
+
+ // Assert that we received the colors that we were expecting
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
+ .isEqualTo(MONET_SYSTEM_PALETTE_PACKAGE + "0CCCCC");
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR))
+ .isEqualTo(MONET_ACCENT_COLOR_PACKAGE + "000111");
+ }
+
+ @Test
public void onWallpaperColorsChanged_preservesWallpaperPickerTheme() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationPromptController.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationPromptController.java
index 721220729a33..d2c1bc10abb0 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationPromptController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationPromptController.java
@@ -106,13 +106,16 @@ public class WindowMagnificationPromptController {
final Notification.Builder notificationBuilder = new Notification.Builder(mContext,
SystemNotificationChannels.ACCESSIBILITY_MAGNIFICATION);
+ final String message = mContext.getString(R.string.window_magnification_prompt_content);
+
notificationBuilder.setSmallIcon(R.drawable.ic_settings_24dp)
.setContentTitle(mContext.getString(R.string.window_magnification_prompt_title))
- .setContentText(mContext.getString(R.string.window_magnification_prompt_content))
+ .setContentText(message)
.setLargeIcon(Icon.createWithResource(mContext,
R.drawable.ic_accessibility_magnification))
.setTicker(mContext.getString(R.string.window_magnification_prompt_title))
.setOnlyAlertOnce(true)
+ .setStyle(new Notification.BigTextStyle().bigText(message))
.setDeleteIntent(createPendingIntent(ACTION_DISMISS))
.setContentIntent(createPendingIntent(ACTION_TURN_ON_IN_SETTINGS))
.setActions(buildTurnOnAction(), buildDismissAction());
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 614863d6b8f5..17e3456e565b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -145,6 +145,7 @@ java_library_static {
"SurfaceFlingerProperties",
"com.android.sysprop.watchdog",
],
+ javac_shard_size: 50,
}
java_genrule {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e8ee18c6f4d4..f0677a23765c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -41,6 +41,7 @@ import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
@@ -6354,18 +6355,71 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
}
- /** Propagates to |nc| the capabilities declared by the underlying networks of |nai|. */
- private void mixInUnderlyingCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) {
- Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
- Network defaultNetwork = getNetwork(getDefaultNetwork());
+ /** Modifies |caps| based on the capabilities of the specified underlying networks. */
+ @VisibleForTesting
+ void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks,
+ @NonNull NetworkCapabilities caps, boolean declaredMetered) {
+ final Network defaultNetwork = getNetwork(getDefaultNetwork());
if (underlyingNetworks == null && defaultNetwork != null) {
// null underlying networks means to track the default.
underlyingNetworks = new Network[] { defaultNetwork };
}
+ int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
+ int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ boolean metered = declaredMetered; // metered if any underlying is metered, or agentMetered
+ boolean roaming = false; // roaming if any underlying is roaming
+ boolean congested = false; // congested if any underlying is congested
+ boolean suspended = true; // suspended if all underlying are suspended
+
+ boolean hadUnderlyingNetworks = false;
+ if (null != underlyingNetworks) {
+ for (Network underlyingNetwork : underlyingNetworks) {
+ final NetworkAgentInfo underlying =
+ getNetworkAgentInfoForNetwork(underlyingNetwork);
+ if (underlying == null) continue;
+
+ final NetworkCapabilities underlyingCaps = underlying.networkCapabilities;
+ hadUnderlyingNetworks = true;
+ for (int underlyingType : underlyingCaps.getTransportTypes()) {
+ transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
+ }
- // TODO(b/124469351): Get capabilities directly from ConnectivityService instead.
- final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
- Vpn.applyUnderlyingCapabilities(cm, underlyingNetworks, nc, nai.declaredMetered);
+ // Merge capabilities of this underlying network. For bandwidth, assume the
+ // worst case.
+ downKbps = NetworkCapabilities.minBandwidth(downKbps,
+ underlyingCaps.getLinkDownstreamBandwidthKbps());
+ upKbps = NetworkCapabilities.minBandwidth(upKbps,
+ underlyingCaps.getLinkUpstreamBandwidthKbps());
+ // If this underlying network is metered, the VPN is metered (it may cost money
+ // to send packets on this network).
+ metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
+ // If this underlying network is roaming, the VPN is roaming (the billing structure
+ // is different than the usual, local one).
+ roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ // If this underlying network is congested, the VPN is congested (the current
+ // condition of the network affects the performance of this network).
+ congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
+ // If this network is not suspended, the VPN is not suspended (the VPN
+ // is able to transfer some data).
+ suspended &= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ }
+ }
+ if (!hadUnderlyingNetworks) {
+ // No idea what the underlying networks are; assume reasonable defaults
+ metered = true;
+ roaming = false;
+ congested = false;
+ suspended = false;
+ }
+
+ caps.setTransportTypes(transportTypes);
+ caps.setLinkDownstreamBandwidthKbps(downKbps);
+ caps.setLinkUpstreamBandwidthKbps(upKbps);
+ caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
+ caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
+ caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
+ caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
}
/**
@@ -6422,7 +6476,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
if (nai.supportsUnderlyingNetworks()) {
- mixInUnderlyingCapabilities(nai, newNc);
+ applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, newNc, nai.declaredMetered);
}
return newNc;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4165200d837a..c7e3b2344f54 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -91,6 +91,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.stats.devicepolicy.DevicePolicyEnums;
import android.text.TextUtils;
@@ -165,6 +166,7 @@ public final class ActiveServices {
public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 15;
public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION = 16;
public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17;
+ public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE = 18;
@IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
FGS_FEATURE_DENIED,
@@ -183,7 +185,8 @@ public final class ActiveServices {
FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST,
FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_FGS_BINDING
+ FGS_FEATURE_ALLOWED_BY_FGS_BINDING,
+ FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE
})
@Retention(RetentionPolicy.SOURCE)
public @interface FgsFeatureRetCode {}
@@ -5287,6 +5290,12 @@ public final class ActiveServices {
}
}
+ if (ret == FGS_FEATURE_DENIED) {
+ if (UserManager.isDeviceInDemoMode(mAm.mContext)) {
+ ret = FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE;
+ }
+ }
+
final String debugInfo =
"[callingPackage: " + callingPackage
+ "; callingUid: " + callingUid
@@ -5340,6 +5349,8 @@ public final class ActiveServices {
return "ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION";
case FGS_FEATURE_ALLOWED_BY_FGS_BINDING:
return "ALLOWED_BY_FGS_BINDING";
+ case FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE:
+ return "ALLOWED_BY_DEVICE_DEMO_MODE";
default:
return "";
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b2f3bff7e277..63128ced8f93 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -253,6 +253,7 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.SharedMemory;
import android.os.ShellCallback;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -348,6 +349,7 @@ import com.android.server.appop.AppOpsService;
import com.android.server.compat.PlatformCompat;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.firewall.IntentFirewall;
+import com.android.server.graphics.fonts.FontManagerInternal;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.pm.Installer;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -4359,6 +4361,11 @@ public class ActivityManagerService extends IActivityManager.Stub
app.info.packageName);
}
}
+ SharedMemory serializedSystemFontMap = null;
+ final FontManagerInternal fm = LocalServices.getService(FontManagerInternal.class);
+ if (fm != null) {
+ serializedSystemFontMap = fm.getSerializedSystemFontMap();
+ }
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
bindApplicationTimeMillis = SystemClock.elapsedRealtime();
@@ -4384,7 +4391,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
- app.mDisabledCompatChanges);
+ app.mDisabledCompatChanges, serializedSystemFontMap);
} else {
thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
null, null, null, testMode,
@@ -4394,7 +4401,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
- app.mDisabledCompatChanges);
+ app.mDisabledCompatChanges, serializedSystemFontMap);
}
if (profilerInfo != null) {
profilerInfo.closeFd();
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 234dcc9d74a5..3445275b76dd 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -18,10 +18,7 @@ package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE;
import static android.net.ConnectivityManager.NETID_UNSET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
@@ -111,7 +108,6 @@ import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
-import com.android.internal.util.ArrayUtils;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
@@ -463,99 +459,6 @@ public class Vpn {
}
/**
- * Updates {@link #mNetworkCapabilities} based on current underlying networks and returns a
- * defensive copy.
- *
- * <p>Does not propagate updated capabilities to apps.
- *
- * @param defaultNetwork underlying network for VPNs following platform's default
- */
- public synchronized NetworkCapabilities updateCapabilities(@Nullable Network defaultNetwork) {
- if (mConfig == null) {
- // VPN is not running.
- return null;
- }
-
- Network[] underlyingNetworks = mConfig.underlyingNetworks;
- if (underlyingNetworks == null && defaultNetwork != null) {
- // null underlying networks means to track the default.
- underlyingNetworks = new Network[] { defaultNetwork };
- }
- // Only apps targeting Q and above can explicitly declare themselves as metered.
- final boolean isAlwaysMetered = mIsPackageTargetingAtLeastQ && mConfig.isMetered;
-
- applyUnderlyingCapabilities(
- mConnectivityManager,
- underlyingNetworks,
- mNetworkCapabilities,
- isAlwaysMetered);
-
- return new NetworkCapabilities(mNetworkCapabilities);
- }
-
- @VisibleForTesting
- public static void applyUnderlyingCapabilities(
- @NonNull final ConnectivityManager cm,
- @Nullable final Network[] underlyingNetworks,
- @NonNull final NetworkCapabilities caps,
- final boolean isAlwaysMetered) {
- int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
- int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
- int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
- boolean metered = isAlwaysMetered; // metered if any underlying is metered, or alwaysMetered
- boolean roaming = false; // roaming if any underlying is roaming
- boolean congested = false; // congested if any underlying is congested
- boolean suspended = true; // suspended if all underlying are suspended
-
- boolean hadUnderlyingNetworks = false;
- if (null != underlyingNetworks) {
- for (Network underlying : underlyingNetworks) {
- // TODO(b/124469351): Get capabilities directly from ConnectivityService instead.
- final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
- if (underlyingCaps == null) continue;
- hadUnderlyingNetworks = true;
- for (int underlyingType : underlyingCaps.getTransportTypes()) {
- transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
- }
-
- // Merge capabilities of this underlying network. For bandwidth, assume the
- // worst case.
- downKbps = NetworkCapabilities.minBandwidth(downKbps,
- underlyingCaps.getLinkDownstreamBandwidthKbps());
- upKbps = NetworkCapabilities.minBandwidth(upKbps,
- underlyingCaps.getLinkUpstreamBandwidthKbps());
- // If this underlying network is metered, the VPN is metered (it may cost money
- // to send packets on this network).
- metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
- // If this underlying network is roaming, the VPN is roaming (the billing structure
- // is different than the usual, local one).
- roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
- // If this underlying network is congested, the VPN is congested (the current
- // condition of the network affects the performance of this network).
- congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
- // If this network is not suspended, the VPN is not suspended (the VPN
- // is able to transfer some data).
- suspended &= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
- }
- }
- if (!hadUnderlyingNetworks) {
- // No idea what the underlying networks are; assume the safer defaults
- metered = true;
- roaming = false;
- congested = false;
- suspended = false;
- }
-
- caps.setTransportTypes(transportTypes);
- caps.setLinkDownstreamBandwidthKbps(downKbps);
- caps.setLinkUpstreamBandwidthKbps(upKbps);
- caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
- caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
- caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
- caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
- }
-
- /**
* Chooses whether to force all connections to go though VPN.
*
* Used to enable/disable legacy VPN lockdown.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 29b413d921e1..d4a19d6bc366 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -53,6 +53,7 @@ import android.hardware.display.AmbientBrightnessDayStats;
import android.hardware.display.BrightnessChangeEvent;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.Curve;
+import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
@@ -1252,11 +1253,19 @@ public final class DisplayManagerService extends SystemService {
mDisplayModeDirector.setShouldAlwaysRespectAppRequestedMode(enabled);
}
-
boolean shouldAlwaysRespectAppRequestedModeInternal() {
return mDisplayModeDirector.shouldAlwaysRespectAppRequestedMode();
}
+ void setRefreshRateSwitchingTypeInternal(@DisplayManager.SwitchingType int newValue) {
+ mDisplayModeDirector.setModeSwitchingType(newValue);
+ }
+
+ @DisplayManager.SwitchingType
+ int getRefreshRateSwitchingTypeInternal() {
+ return mDisplayModeDirector.getModeSwitchingType();
+ }
+
private void setBrightnessConfigurationForUserInternal(
@Nullable BrightnessConfiguration c, @UserIdInt int userId,
@Nullable String packageName) {
@@ -2595,6 +2604,32 @@ public final class DisplayManagerService extends SystemService {
}
}
+ @Override // Binder call
+ public void setRefreshRateSwitchingType(int newValue) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE,
+ "Permission required to modify refresh rate switching type.");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ setRefreshRateSwitchingTypeInternal(newValue);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ public int getRefreshRateSwitchingType() {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE,
+ "Permission required read refresh rate switching type.");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getRefreshRateSwitchingTypeInternal();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private boolean validatePackageName(int uid, String packageName) {
if (packageName != null) {
String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 329081a8391f..95918945eecd 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -16,7 +16,6 @@
package com.android.server.display;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -53,8 +52,6 @@ import com.android.server.display.utils.AmbientFilterFactory;
import com.android.server.utils.DeviceConfigInterface;
import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -110,28 +107,11 @@ public class DisplayModeDirector {
private boolean mAlwaysRespectAppRequest;
- @IntDef(prefix = {"SWITCHING_TYPE_"}, value = {
- SWITCHING_TYPE_NONE,
- SWITCHING_TYPE_WITHIN_GROUPS,
- SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface SwitchingType {}
-
- // No mode switching will happen.
- public static final int SWITCHING_TYPE_NONE = 0;
- // Allow only refresh rate switching between modes in the same configuration group. This way
- // only switches without visual interruptions for the user will be allowed.
- public static final int SWITCHING_TYPE_WITHIN_GROUPS = 1;
- // Allow refresh rate switching between all refresh rates even if the switch with have visual
- // interruptions for the user.
- public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2;
-
/**
* The allowed refresh rate switching type. This is used by SurfaceFlinger.
*/
- @SwitchingType
- private int mModeSwitchingType = SWITCHING_TYPE_WITHIN_GROUPS;
+ @DisplayManager.SwitchingType
+ private int mModeSwitchingType = DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS;
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
this(context, handler, new RealInjector());
@@ -337,7 +317,7 @@ public class DisplayModeDirector {
if (availableModes.length > 0) {
baseModeId = availableModes[0];
}
- if (mModeSwitchingType == SWITCHING_TYPE_NONE) {
+ if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) {
Display.Mode baseMode = null;
for (Display.Mode mode : modes) {
if (mode.getModeId() == baseModeId) {
@@ -359,7 +339,7 @@ public class DisplayModeDirector {
}
boolean allowGroupSwitching =
- mModeSwitchingType == SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS;
+ mModeSwitchingType == DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS;
return new DesiredDisplayModeSpecs(baseModeId,
allowGroupSwitching,
new RefreshRateRange(
@@ -450,18 +430,21 @@ public class DisplayModeDirector {
/**
* Sets the display mode switching type.
- * @param type
+ * @param newType
*/
- public void setModeSwitchingType(@SwitchingType int type) {
+ public void setModeSwitchingType(@DisplayManager.SwitchingType int newType) {
synchronized (mLock) {
- mModeSwitchingType = type;
+ if (newType != mModeSwitchingType) {
+ mModeSwitchingType = newType;
+ notifyDesiredDisplayModeSpecsChangedLocked();
+ }
}
}
/**
* Returns the display mode switching type.
*/
- @SwitchingType
+ @DisplayManager.SwitchingType
public int getModeSwitchingType() {
synchronized (mLock) {
return mModeSwitchingType;
@@ -583,13 +566,13 @@ public class DisplayModeDirector {
}
}
- private static String switchingTypeToString(@SwitchingType int type) {
+ private static String switchingTypeToString(@DisplayManager.SwitchingType int type) {
switch (type) {
- case SWITCHING_TYPE_NONE:
+ case DisplayManager.SWITCHING_TYPE_NONE:
return "SWITCHING_TYPE_NONE";
- case SWITCHING_TYPE_WITHIN_GROUPS:
+ case DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS:
return "SWITCHING_TYPE_WITHIN_GROUPS";
- case SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS:
+ case DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS:
return "SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS";
default:
return "Unknown SwitchingType " + type;
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java b/services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java
new file mode 100644
index 000000000000..e4b7b03a8e07
--- /dev/null
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.graphics.fonts;
+
+import android.annotation.Nullable;
+import android.os.SharedMemory;
+
+/** Local interface for {@link FontManagerService}. */
+public interface FontManagerInternal {
+
+ /** Returns a SharedMemory in which the system font map is serialized. */
+ @Nullable SharedMemory getSerializedSystemFontMap();
+}
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
new file mode 100644
index 000000000000..521ce6973522
--- /dev/null
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.graphics.fonts;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
+import java.io.IOException;
+
+/** A service for managing system fonts. */
+// TODO(b/173619554): Add API to update fonts.
+public final class FontManagerService {
+
+ private static final String TAG = "FontManagerService";
+
+ /** Class to manage FontManagerService's lifecycle. */
+ public static final class Lifecycle extends SystemService {
+ private final FontManagerService mService;
+
+ public Lifecycle(@NonNull Context context) {
+ super(context);
+ mService = new FontManagerService();
+ }
+
+ @Override
+ public void onStart() {
+ LocalServices.addService(FontManagerInternal.class,
+ new FontManagerInternal() {
+ @Override
+ @Nullable
+ public SharedMemory getSerializedSystemFontMap() {
+ return mService.getSerializedSystemFontMap();
+ }
+ });
+ }
+ }
+
+ @GuardedBy("this")
+ @Nullable
+ private SharedMemory mSerializedSystemFontMap = null;
+
+ @Nullable
+ private SharedMemory getSerializedSystemFontMap() {
+ if (!Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+ return null;
+ }
+ synchronized (FontManagerService.this) {
+ if (mSerializedSystemFontMap == null) {
+ mSerializedSystemFontMap = createSerializedSystemFontMapLocked();
+ }
+ return mSerializedSystemFontMap;
+ }
+ }
+
+ @Nullable
+ private SharedMemory createSerializedSystemFontMapLocked() {
+ // TODO(b/173619554): use updated fonts.
+ try {
+ return Typeface.serializeFontMap(Typeface.getSystemFontMap());
+ } catch (IOException | ErrnoException e) {
+ Slog.e(TAG, "Failed to serialize SystemServer system font map", e);
+ }
+ return null;
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/CecMessageBuffer.java b/services/core/java/com/android/server/hdmi/CecMessageBuffer.java
new file mode 100644
index 000000000000..8f971fd7db07
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/CecMessageBuffer.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Buffer for processing the incoming CEC messages while allocating logical addresses.
+ */
+final class CecMessageBuffer {
+ private List<HdmiCecMessage> mBuffer = new ArrayList<>();
+ private HdmiControlService mHdmiControlService;
+
+ CecMessageBuffer(HdmiControlService hdmiControlService) {
+ mHdmiControlService = hdmiControlService;
+ }
+
+ /**
+ * Adds a message to the buffer.
+ * Only certain types of messages need to be buffered.
+ * @param message The message to add to the buffer
+ * @return Whether the message was added to the buffer
+ */
+ public boolean bufferMessage(HdmiCecMessage message) {
+ switch (message.getOpcode()) {
+ case Constants.MESSAGE_ACTIVE_SOURCE:
+ bufferActiveSource(message);
+ return true;
+ case Constants.MESSAGE_IMAGE_VIEW_ON:
+ case Constants.MESSAGE_TEXT_VIEW_ON:
+ bufferImageOrTextViewOn(message);
+ return true;
+ case Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST:
+ bufferSystemAudioModeRequest(message);
+ return true;
+ // Add here if new message that needs to buffer
+ default:
+ // Do not need to buffer messages other than above
+ return false;
+ }
+ }
+
+ /**
+ * Process all messages in the buffer.
+ */
+ public void processMessages() {
+ for (final HdmiCecMessage message : mBuffer) {
+ mHdmiControlService.runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ mHdmiControlService.handleCecCommand(message);
+ }
+ });
+ }
+ mBuffer.clear();
+ }
+
+ private void bufferActiveSource(HdmiCecMessage message) {
+ if (!replaceMessageIfBuffered(message, Constants.MESSAGE_ACTIVE_SOURCE)) {
+ mBuffer.add(message);
+ }
+ }
+
+ private void bufferImageOrTextViewOn(HdmiCecMessage message) {
+ if (!replaceMessageIfBuffered(message, Constants.MESSAGE_IMAGE_VIEW_ON)
+ && !replaceMessageIfBuffered(message, Constants.MESSAGE_TEXT_VIEW_ON)) {
+ mBuffer.add(message);
+ }
+ }
+
+ private void bufferSystemAudioModeRequest(HdmiCecMessage message) {
+ if (!replaceMessageIfBuffered(message, Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST)) {
+ mBuffer.add(message);
+ }
+ }
+
+ // Returns true if the message is replaced
+ private boolean replaceMessageIfBuffered(HdmiCecMessage message, int opcode) {
+ for (int i = 0; i < mBuffer.size(); i++) {
+ HdmiCecMessage bufferedMessage = mBuffer.get(i);
+ if (bufferedMessage.getOpcode() == opcode) {
+ mBuffer.set(i, message);
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index 2374ece1dd65..a261fa1f2741 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -22,19 +22,12 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
-import android.database.ContentObserver;
import android.hardware.hdmi.HdmiControlManager;
-import android.net.Uri;
import android.os.Environment;
-import android.os.Handler;
-import android.os.Looper;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.provider.Settings.Global;
-import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -95,23 +88,6 @@ public class HdmiCecConfig {
@Nullable private final CecSettings mProductConfig;
@Nullable private final CecSettings mVendorOverride;
- private final ArrayMap<Setting, Set<SettingChangeListener>>
- mSettingChangeListeners = new ArrayMap<>();
-
- private SettingsObserver mSettingsObserver;
-
- /**
- * Listener used to get notifications when value of a setting changes.
- */
- public interface SettingChangeListener {
- /**
- * Called when value of a setting changes.
- *
- * @param setting name of a CEC setting that changed
- */
- void onChange(@NonNull @CecSettingName String setting);
- }
-
/**
* Setting storage input/output helper class.
*/
@@ -183,18 +159,6 @@ public class HdmiCecConfig {
}
}
- private class SettingsObserver extends ContentObserver {
- SettingsObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- String setting = uri.getLastPathSegment();
- HdmiCecConfig.this.notifyGlobalSettingChanged(setting);
- }
- }
-
@VisibleForTesting
HdmiCecConfig(@NonNull Context context,
@NonNull StorageAdapter storageAdapter,
@@ -347,7 +311,6 @@ public class HdmiCecConfig {
} else if (storage == STORAGE_SHARED_PREFS) {
Slog.d(TAG, "Setting '" + storageKey + "' shared pref.");
mStorageAdapter.storeSharedPref(storageKey, value);
- notifySettingChanged(setting);
}
}
@@ -355,103 +318,6 @@ public class HdmiCecConfig {
return Integer.decode(value.getIntValue());
}
- private void notifyGlobalSettingChanged(String setting) {
- switch (setting) {
- case Global.HDMI_CONTROL_ENABLED:
- notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
- break;
- case Global.HDMI_CEC_VERSION:
- notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION);
- break;
- case Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP:
- notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
- break;
- }
- }
-
- private void notifySettingChanged(@NonNull @CecSettingName String name) {
- Setting setting = getSetting(name);
- if (setting == null) {
- throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
- }
- notifySettingChanged(setting);
- }
-
- private void notifySettingChanged(@NonNull Setting setting) {
- Set<SettingChangeListener> listeners = mSettingChangeListeners.get(setting);
- if (listeners == null) {
- return; // No listeners registered, do nothing.
- }
- for (SettingChangeListener listener: listeners) {
- listener.onChange(setting.getName());
- }
- }
-
- /**
- * This method registers Global Setting change observer.
- * Needs to be called once after initialization of HdmiCecConfig.
- */
- public void registerGlobalSettingsObserver(Looper looper) {
- Handler handler = new Handler(looper);
- mSettingsObserver = new SettingsObserver(handler);
- ContentResolver resolver = mContext.getContentResolver();
- String[] settings = new String[] {
- Global.HDMI_CONTROL_ENABLED,
- Global.HDMI_CEC_VERSION,
- Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
- };
- for (String setting: settings) {
- resolver.registerContentObserver(Global.getUriFor(setting), false,
- mSettingsObserver, UserHandle.USER_ALL);
- }
- }
-
- /**
- * This method unregisters Global Setting change observer.
- */
- public void unregisterGlobalSettingsObserver() {
- ContentResolver resolver = mContext.getContentResolver();
- resolver.unregisterContentObserver(mSettingsObserver);
- }
-
- /**
- * Register change listener for a given setting name.
- */
- public void registerChangeListener(@NonNull @CecSettingName String name,
- SettingChangeListener listener) {
- Setting setting = getSetting(name);
- if (setting == null) {
- throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
- }
- @Storage int storage = getStorage(setting);
- if (storage != STORAGE_GLOBAL_SETTINGS && storage != STORAGE_SHARED_PREFS) {
- throw new IllegalArgumentException("Change listeners for setting '" + name
- + "' not supported.");
- }
- if (!mSettingChangeListeners.containsKey(setting)) {
- mSettingChangeListeners.put(setting, new HashSet<>());
- }
- mSettingChangeListeners.get(setting).add(listener);
- }
-
- /**
- * Remove change listener for a given setting name.
- */
- public void removeChangeListener(@NonNull @CecSettingName String name,
- SettingChangeListener listener) {
- Setting setting = getSetting(name);
- if (setting == null) {
- throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
- }
- if (mSettingChangeListeners.containsKey(setting)) {
- Set<SettingChangeListener> listeners = mSettingChangeListeners.get(setting);
- listeners.remove(listener);
- if (listeners.isEmpty()) {
- mSettingChangeListeners.remove(setting);
- }
- }
- }
-
/**
* Returns a list of all settings based on the XML metadata.
*/
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index fd825d6f6288..56b73ba04d89 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -405,74 +405,7 @@ public class HdmiControlService extends SystemService {
// Use getAtomWriter() instead of accessing directly, to allow dependency injection for testing.
private HdmiCecAtomWriter mAtomWriter = new HdmiCecAtomWriter();
- // Buffer for processing the incoming cec messages while allocating logical addresses.
- private final class CecMessageBuffer {
- private List<HdmiCecMessage> mBuffer = new ArrayList<>();
-
- public boolean bufferMessage(HdmiCecMessage message) {
- switch (message.getOpcode()) {
- case Constants.MESSAGE_ACTIVE_SOURCE:
- bufferActiveSource(message);
- return true;
- case Constants.MESSAGE_IMAGE_VIEW_ON:
- case Constants.MESSAGE_TEXT_VIEW_ON:
- bufferImageOrTextViewOn(message);
- return true;
- case Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST:
- bufferSystemAudioModeRequest(message);
- return true;
- // Add here if new message that needs to buffer
- default:
- // Do not need to buffer messages other than above
- return false;
- }
- }
-
- public void processMessages() {
- for (final HdmiCecMessage message : mBuffer) {
- runOnServiceThread(new Runnable() {
- @Override
- public void run() {
- handleCecCommand(message);
- }
- });
- }
- mBuffer.clear();
- }
-
- private void bufferActiveSource(HdmiCecMessage message) {
- if (!replaceMessageIfBuffered(message, Constants.MESSAGE_ACTIVE_SOURCE)) {
- mBuffer.add(message);
- }
- }
-
- private void bufferImageOrTextViewOn(HdmiCecMessage message) {
- if (!replaceMessageIfBuffered(message, Constants.MESSAGE_IMAGE_VIEW_ON) &&
- !replaceMessageIfBuffered(message, Constants.MESSAGE_TEXT_VIEW_ON)) {
- mBuffer.add(message);
- }
- }
-
- private void bufferSystemAudioModeRequest(HdmiCecMessage message) {
- if (!replaceMessageIfBuffered(message, Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST)) {
- mBuffer.add(message);
- }
- }
-
- // Returns true if the message is replaced
- private boolean replaceMessageIfBuffered(HdmiCecMessage message, int opcode) {
- for (int i = 0; i < mBuffer.size(); i++) {
- HdmiCecMessage bufferedMessage = mBuffer.get(i);
- if (bufferedMessage.getOpcode() == opcode) {
- mBuffer.set(i, message);
- return true;
- }
- }
- return false;
- }
- }
-
- private final CecMessageBuffer mCecMessageBuffer = new CecMessageBuffer();
+ private CecMessageBuffer mCecMessageBuffer = new CecMessageBuffer(this);
private final SelectRequestBuffer mSelectRequestBuffer = new SelectRequestBuffer();
@@ -563,7 +496,6 @@ public class HdmiControlService extends SystemService {
if (mMessageValidator == null) {
mMessageValidator = new HdmiCecMessageValidator(this);
}
- mHdmiCecConfig.registerGlobalSettingsObserver(mIoLooper);
}
private void bootCompleted() {
@@ -988,6 +920,11 @@ public class HdmiControlService extends SystemService {
mMessageValidator = messageValidator;
}
+ @VisibleForTesting
+ void setCecMessageBuffer(CecMessageBuffer cecMessageBuffer) {
+ this.mCecMessageBuffer = cecMessageBuffer;
+ }
+
/**
* Returns {@link Looper} of main thread. Use this {@link Looper} instance
* for tasks that are running on main service thread.
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index f2eb5af51616..42aad7d7ad5c 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -95,6 +95,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.XmlUtils;
import com.android.server.DisplayThread;
@@ -146,6 +147,16 @@ public class InputManagerService extends IInputManager.Stub
private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;
+ /**
+ * We know the issue and are working to fix it, so suppressing the toast to not annoy
+ * dogfooders.
+ *
+ * TODO(b/169067926): Remove this
+ */
+ private static final String[] PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST = {
+ "com.snapchat.android" // b/173297887
+ };
+
// Pointer to native input manager service object.
private final long mPtr;
@@ -2091,6 +2102,10 @@ public class InputManagerService extends IInputManager.Stub
// Native callback
private void notifyUntrustedTouch(String packageName) {
// TODO(b/169067926): Remove toast after gathering feedback on dogfood.
+ if (ArrayUtils.contains(PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
+ Log.i(TAG, "Suppressing untrusted touch toast for " + packageName);
+ return;
+ }
DisplayThread.getHandler().post(() ->
Toast.makeText(mContext,
"Touch obscured by " + packageName
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 76b9c8619cfc..ee860e3ac6d7 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -230,9 +230,9 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.StatsEvent;
-import android.util.Xml;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
+import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -257,7 +257,6 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
@@ -286,9 +285,7 @@ import libcore.io.IoUtils;
import org.json.JSONException;
import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -737,7 +734,7 @@ public class NotificationManagerService extends SystemService {
null,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
if (candidate != null && validAssistants.contains(candidate)) {
- setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true);
+ setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true, false);
return true;
}
return false;
@@ -4913,7 +4910,8 @@ public class NotificationManagerService extends SystemService {
}
final long identity = Binder.clearCallingIdentity();
try {
- setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
+ setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted,
+ true);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -5164,7 +5162,7 @@ public class NotificationManagerService extends SystemService {
@VisibleForTesting
protected void setNotificationAssistantAccessGrantedForUserInternal(
- ComponentName assistant, int baseUserId, boolean granted) {
+ ComponentName assistant, int baseUserId, boolean granted, boolean userSet) {
List<UserInfo> users = mUm.getEnabledProfiles(baseUserId);
if (users != null) {
for (UserInfo user : users) {
@@ -5174,7 +5172,7 @@ public class NotificationManagerService extends SystemService {
mAssistants.getAllowedComponents(userId));
if (allowedAssistant != null) {
setNotificationAssistantAccessGrantedForUserInternal(
- allowedAssistant, userId, false);
+ allowedAssistant, userId, false, userSet);
}
continue;
}
@@ -5183,7 +5181,7 @@ public class NotificationManagerService extends SystemService {
mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
userId, false, granted);
mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
- userId, true, granted);
+ userId, true, granted, userSet);
getContext().sendBroadcastAsUser(
new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
@@ -9338,7 +9336,7 @@ public class NotificationManagerService extends SystemService {
@Override
protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
- boolean isPrimary, boolean enabled) {
+ boolean isPrimary, boolean enabled, boolean userSet) {
// Ensures that only one component is enabled at a time
if (enabled) {
List<ComponentName> allowedComponents = getAllowedComponents(userId);
@@ -9346,10 +9344,10 @@ public class NotificationManagerService extends SystemService {
ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents);
if (currentComponent.flattenToString().equals(pkgOrComponent)) return;
setNotificationAssistantAccessGrantedForUserInternal(
- currentComponent, userId, false);
+ currentComponent, userId, false, userSet);
}
}
- super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled);
+ super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet);
}
private boolean isVerboseLogEnabled() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 85659edd1321..8fc9cb725859 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1738,6 +1738,7 @@ public class PackageManagerService extends IPackageManager.Stub
final @Nullable String mOverlayConfigSignaturePackage;
final @Nullable String mRecentsPackage;
+ @GuardedBy("mLock")
private final PackageUsage mPackageUsage = new PackageUsage();
private final CompilerStats mCompilerStats = new CompilerStats();
@@ -2210,22 +2211,27 @@ public class PackageManagerService extends IPackageManager.Stub
res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
+ final PermissionManagerServiceInternal.PackageInstalledParams.Builder
+ permissionParamsBuilder =
+ new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
final List<String> grantedPermissionsList;
if (grantPermissions) {
if (grantedPermissions != null) {
- grantedPermissionsList = Arrays.asList(grantedPermissions);
+ permissionParamsBuilder.setGrantedPermissions(Arrays.asList(
+ grantedPermissions));
} else {
- grantedPermissionsList = res.pkg.getRequestedPermissions();
+ permissionParamsBuilder.setGrantedPermissions(
+ res.pkg.getRequestedPermissions());
}
- } else {
- grantedPermissionsList = Collections.emptyList();
}
- if (allowlistedRestrictedPermissions == null) {
- allowlistedRestrictedPermissions = Collections.emptyList();
+ if (allowlistedRestrictedPermissions != null) {
+ permissionParamsBuilder.setAllowlistedRestrictedPermissions(
+ allowlistedRestrictedPermissions);
}
+ permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
for (final int userId : res.newUsers) {
- mPermissionManager.onPackageInstalled(res.pkg, grantedPermissionsList,
- allowlistedRestrictedPermissions, autoRevokePermissionsMode, userId);
+ mPermissionManager.onPackageInstalled(res.pkg, permissionParamsBuilder.build(),
+ userId);
}
final String installerPackageName =
@@ -3312,6 +3318,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Stub packages must either be replaced with full versions in the /data
// partition or be disabled.
final List<String> stubSystemApps = new ArrayList<>();
+ final int[] userIds = mUserManager.getUserIds();
if (!mOnlyCore) {
// do this first before mucking with mPackages for the "expecting better" case
final int numPackages = mPackages.size();
@@ -3362,15 +3369,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
- mSettings.mPackages.removeAt(index);
logCriticalInfo(Log.WARN, "System package " + ps.name
+ " no longer exists; it's data will be wiped");
-
- // Assume package is truly gone and wipe residual permissions.
- mPermissionManager.updatePermissions(ps.name, null);
-
- // Actual deletion of code and data will be handled by later
- // reconciliation step
+ removePackageDataLIF(ps, userIds, null, 0, false);
} else {
// we still have a disabled system package, but, it still might have
// been removed. check the code path still exists and check there's
@@ -3429,7 +3430,6 @@ public class PackageManagerService extends IPackageManager.Stub
// Remove disable package settings for updated system apps that were
// removed via an OTA. If the update is no longer present, remove the
// app completely. Otherwise, revoke their system privileges.
- final int[] userIds = mUserManager.getUserIds();
for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
final AndroidPackage pkg = mPackages.get(packageName);
@@ -3764,7 +3764,6 @@ public class PackageManagerService extends IPackageManager.Stub
UserHandle.USER_SYSTEM).getLongVersionCode());
// Initialize InstantAppRegistry's Instant App list for all users.
- final int[] userIds = UserManagerService.getInstance().getUserIds();
for (AndroidPackage pkg : mPackages.values()) {
if (pkg.isSystem()) {
continue;
@@ -3930,7 +3929,12 @@ public class PackageManagerService extends IPackageManager.Stub
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
}
- mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
+ final int[] userIds = mUserManager.getUserIds();
+ for (final int userId : userIds) {
+ mPermissionManager.onPackageInstalled(pkg,
+ PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
+ userId);
+ }
writeSettingsLPrTEMP();
}
} catch (PackageManagerException e) {
@@ -10630,13 +10634,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
public void shutdown() {
- mPackageUsage.writeNow(mSettings.mPackages);
mCompilerStats.writeNow();
mDexManager.writePackageDexUsageNow();
PackageWatchdog.getInstance(mContext).writeNow();
- // This is the last chance to write out pending restriction settings
synchronized (mLock) {
+ mPackageUsage.writeNow(mSettings.mPackages);
+
+ // This is the last chance to write out pending restriction settings
if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
for (int userId : mDirtyUsers) {
@@ -13671,14 +13676,16 @@ public class PackageManagerService extends IPackageManager.Stub
if (installed) {
if (pkgSetting.pkg != null) {
+ final PermissionManagerServiceInternal.PackageInstalledParams.Builder
+ permissionParamsBuilder =
+ new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS)
!= 0) {
- allowlistedRestrictedPermissions = pkgSetting.pkg.getRequestedPermissions();
- } else if (allowlistedRestrictedPermissions == null) {
- allowlistedRestrictedPermissions = Collections.emptyList();
+ permissionParamsBuilder.setAllowlistedRestrictedPermissions(
+ pkgSetting.pkg.getRequestedPermissions());
}
- mPermissionManager.onPackageInstalled(pkgSetting.pkg, Collections.emptyList(),
- allowlistedRestrictedPermissions, MODE_DEFAULT, userId);
+ mPermissionManager.onPackageInstalled(pkgSetting.pkg,
+ permissionParamsBuilder.build(), userId);
}
if (pkgSetting.pkg != null) {
@@ -13937,7 +13944,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps == null) {
- throw new IllegalArgumentException("Unknown target package: " + packageName);
+ return null;
}
final PackageUserState pus = ps.readUserState(userId);
final Bundle allExtras = new Bundle();
@@ -16480,8 +16487,6 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getPath());
synchronized (mLock) {
-// NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions
- mPermissionManager.updatePermissions(pkgName, pkg);
// For system-bundled packages, we assume that installing an upgraded version
// of the package implies that the user actually wants to run that new code,
// so we enable the package.
@@ -19501,13 +19506,20 @@ public class PackageManagerService extends IPackageManager.Stub
if (outInfo != null) {
outInfo.removedAppId = removedAppId;
}
- final SharedUserSetting sus = deletedPs.getSharedUser();
- List<AndroidPackage> sharedUserPkgs = sus != null ? sus.getPackages() : null;
- if (sharedUserPkgs == null) {
- sharedUserPkgs = Collections.emptyList();
+ if (!mSettings.isDisabledSystemPackageLPr(packageName)) {
+ // If we don't have a disabled system package to reinstall, the package is
+ // really gone and its permission state should be removed.
+ final SharedUserSetting sus = deletedPs.getSharedUser();
+ List<AndroidPackage> sharedUserPkgs = sus != null ? sus.getPackages()
+ : null;
+ if (sharedUserPkgs == null) {
+ sharedUserPkgs = Collections.emptyList();
+ }
+ for (final int userId : allUserHandles) {
+ mPermissionManager.onPackageUninstalled(packageName, deletedPs.appId,
+ deletedPs.pkg, sharedUserPkgs, userId);
+ }
}
- mPermissionManager.onPackageStateRemoved(packageName, deletedPs.appId,
- deletedPs.pkg, sharedUserPkgs);
clearPackagePreferredActivitiesLPw(
deletedPs.name, changedUsers, UserHandle.USER_ALL);
}
@@ -19696,10 +19708,6 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
- // The update permissions method below will take care of removing obsolete permissions
- // and granting install permissions.
- mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
-
final boolean applyUserRestrictions = origUserHandles != null;
if (applyUserRestrictions) {
boolean installedStateChanged = false;
@@ -19718,8 +19726,6 @@ public class PackageManagerService extends IPackageManager.Stub
if (installed) {
ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
}
-
- mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
// Regardless of writeSettings we need to ensure that this restriction
// state propagation is persisted
@@ -19728,6 +19734,17 @@ public class PackageManagerService extends IPackageManager.Stub
mSettings.writeKernelMappingLPr(ps);
}
}
+
+ for (final int userId : allUserHandles) {
+ // The method below will take care of removing obsolete permissions and granting
+ // install permissions.
+ mPermissionManager.onPackageInstalled(pkg,
+ PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT, userId);
+ if (applyUserRestrictions) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ }
+ }
+
// can downgrade to reader here
if (writeSettings) {
writeSettingsLPrTEMP();
@@ -20026,6 +20043,11 @@ public class PackageManagerService extends IPackageManager.Stub
destroyAppProfilesLIF(pkg);
+ final SharedUserSetting sus = ps.getSharedUser();
+ List<AndroidPackage> sharedUserPkgs = sus != null ? sus.getPackages() : null;
+ if (sharedUserPkgs == null) {
+ sharedUserPkgs = Collections.emptyList();
+ }
final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds()
: new int[] {userId};
for (int nextUserId : userIds) {
@@ -20040,7 +20062,8 @@ public class PackageManagerService extends IPackageManager.Stub
clearDefaultBrowserIfNeededForUser(ps.name, nextUserId);
removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId);
clearPackagePreferredActivities(ps.name, nextUserId);
- mPermissionManager.resetRuntimePermissions(pkg, nextUserId);
+ mPermissionManager.onPackageUninstalled(ps.name, ps.appId, pkg, sharedUserPkgs,
+ nextUserId);
}
if (outInfo != null) {
@@ -23562,7 +23585,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Note: this code block is executed with the Installer lock
// already held, since it's invoked as a side-effect of
// executeBatchLI()
- if ((e != null) && pkg.isSystem()) {
+ if (e != null) {
logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
+ ", but trying to recover: " + e);
destroyAppDataLeafLIF(pkg, userId, flags);
@@ -26032,7 +26055,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
boolean isHistoricalPackageUsageAvailable() {
- return mPackageUsage.isHistoricalPackageUsageAvailable();
+ synchronized (mLock) {
+ return mPackageUsage.isHistoricalPackageUsageAvailable();
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 9aa1a621a760..9720819a62ab 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -146,7 +146,7 @@ class PackageManagerShellCommand extends ShellCommand {
final IPackageManager mInterface;
final IPermissionManager mPermissionManager;
- final Context mShellPackageContext;
+ final Context mContext;
final private WeakHashMap<String, Resources> mResourceCache =
new WeakHashMap<String, Resources>();
int mTargetUser;
@@ -158,12 +158,7 @@ class PackageManagerShellCommand extends ShellCommand {
PackageManagerService service, IPermissionManager permissionManager, Context context) {
mInterface = service;
mPermissionManager = permissionManager;
- try {
- mShellPackageContext = context.createPackageContext("com.android.shell", 0);
- } catch (NameNotFoundException e) {
- // should not happen
- throw new RuntimeException(e);
- }
+ mContext = context;
}
@Override
@@ -486,8 +481,17 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
+ final Context shellPackageContext;
+ try {
+ shellPackageContext = mContext.createPackageContextAsUser(
+ "com.android.shell", 0, Binder.getCallingUserHandle());
+ } catch (NameNotFoundException e) {
+ // should not happen
+ throw new RuntimeException(e);
+ }
+
final LocalIntentReceiver receiver = new LocalIntentReceiver();
- RollbackManager rm = mShellPackageContext.getSystemService(RollbackManager.class);
+ RollbackManager rm = shellPackageContext.getSystemService(RollbackManager.class);
RollbackInfo rollback = null;
for (RollbackInfo r : rm.getAvailableRollbacks()) {
for (PackageRollbackInfo info : r.getPackages()) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 52bb3d772387..48e18f1b8b38 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -154,7 +154,6 @@ import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultBrowserProvider;
import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultDialerProvider;
import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultHomeProvider;
-import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.SoftRestrictedPermissionPolicy;
@@ -4139,17 +4138,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*
* @param packageName The package that is updated
* @param pkg The package that is updated, or {@code null} if package is deleted
- * @param allPackages All currently known packages
- * @param callback Callback to call after permission changes
*/
- private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg,
- @NonNull PermissionCallback callback) {
+ private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {
// If the package is being deleted, update the permissions of all the apps
final int flags =
(pkg == null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG
: UPDATE_PERMISSIONS_REPLACE_PKG);
updatePermissions(
- packageName, pkg, getVolumeUuidForPackage(pkg), flags, callback);
+ packageName, pkg, getVolumeUuidForPackage(pkg), flags, mDefaultPermissionCallback);
}
/**
@@ -4712,13 +4708,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return userState.getUidState(appId);
}
- private void removeAppIdState(@AppIdInt int appId) {
+ private void removeUidState(@AppIdInt int appId, @UserIdInt int userId) {
synchronized (mLock) {
- final int[] userIds = mState.getUserIds();
- for (final int userId : userIds) {
- final UserPermissionState userState = mState.getUserState(userId);
- userState.removeUidState(appId);
+ final UserPermissionState userState = mState.getUserState(userId);
+ if (userState == null) {
+ return;
}
+ userState.removeUidState(appId);
}
}
@@ -4947,17 +4943,19 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private void onPackageInstalledInternal(@NonNull AndroidPackage pkg,
- @NonNull List<String> grantedPermissions,
- @NonNull List<String> allowlistedRestrictedPermissions, int autoRevokePermissionsMode,
+ @NonNull PermissionManagerServiceInternal.PackageInstalledParams params,
@UserIdInt int userId) {
- addAllowlistedRestrictedPermissionsInternal(pkg, allowlistedRestrictedPermissions,
+ updatePermissions(pkg.getPackageName(), pkg);
+ addAllowlistedRestrictedPermissionsInternal(pkg,
+ params.getAllowlistedRestrictedPermissions(),
FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
+ final int autoRevokePermissionsMode = params.getAutoRevokePermissionsMode();
if (autoRevokePermissionsMode == AppOpsManager.MODE_ALLOWED
|| autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED) {
setAutoRevokeExemptedInternal(pkg,
autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED, userId);
}
- grantRequestedRuntimePermissionsInternal(pkg, grantedPermissions, userId);
+ grantRequestedRuntimePermissionsInternal(pkg, params.getGrantedPermissions(), userId);
}
private void addAllowlistedRestrictedPermissionsInternal(@NonNull AndroidPackage pkg,
@@ -4978,25 +4976,34 @@ public class PermissionManagerService extends IPermissionManager.Stub {
removeAllPermissionsInternal(pkg);
}
- private void onPackageStateRemovedInternal(@NonNull String packageName, int appId,
- @Nullable AndroidPackage pkg, @NonNull List<AndroidPackage> sharedUserPkgs) {
- if (sharedUserPkgs.isEmpty()
- && mPackageManagerInt.getDisabledSystemPackage(packageName) == null) {
- removeAppIdState(appId);
+ private void onPackageUninstalledInternal(@NonNull String packageName, int appId,
+ @Nullable AndroidPackage pkg, @NonNull List<AndroidPackage> sharedUserPkgs,
+ @UserIdInt int userId) {
+ // TODO: Move these checks to check PackageState to be more reliable.
+ // System packages should always have an available APK.
+ if (pkg != null && pkg.isSystem()
+ // We may be fully removing invalid system packages during boot, and in that case we
+ // do want to remove their permission state. So make sure that the package is only
+ // being marked as uninstalled instead of fully removed.
+ && mPackageManagerInt.getPackage(packageName) != null) {
+ // If we are only marking a system package as uninstalled, we need to keep its
+ // pregranted permission state so that it still works once it gets reinstalled, thus
+ // only reset the user modifications to its permission state.
+ resetRuntimePermissionsInternal(pkg, userId);
+ return;
}
- updatePermissions(packageName, null, mDefaultPermissionCallback);
- if (!sharedUserPkgs.isEmpty()) {
+ updatePermissions(packageName, null);
+ if (sharedUserPkgs.isEmpty()) {
+ removeUidState(appId, userId);
+ } else {
// Remove permissions associated with package. Since runtime
// permissions are per user we have to kill the removed package
// or packages running under the shared user of the removed
// package if revoking the permissions requested only by the removed
// package is successful and this causes a change in gids.
- boolean shouldKill = false;
- for (int userId : UserManagerService.getInstance().getUserIds()) {
- final int userIdToKill = revokeSharedUserPermissionsForDeletedPackageInternal(pkg,
- sharedUserPkgs, userId);
- shouldKill |= userIdToKill != UserHandle.USER_NULL;
- }
+ final int userIdToKill = revokeSharedUserPermissionsForDeletedPackageInternal(pkg,
+ sharedUserPkgs, userId);
+ final boolean shouldKill = userIdToKill != UserHandle.USER_NULL;
// If gids changed, kill all affected packages.
if (shouldKill) {
mHandler.post(() -> {
@@ -5140,11 +5147,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return PermissionManagerService.this.getAppOpPermissionPackagesInternal(permissionName);
}
@Override
- public void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {
- PermissionManagerService.this
- .updatePermissions(packageName, pkg, mDefaultPermissionCallback);
- }
- @Override
public void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdated) {
PermissionManagerService.this
.updateAllPermissions(volumeUuid, sdkUpdated, mDefaultPermissionCallback);
@@ -5411,16 +5413,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void onPackageInstalled(@NonNull AndroidPackage pkg,
- @NonNull List<String> grantedPermissions,
- @NonNull List<String> allowlistedRestrictedPermissions,
- int autoRevokePermissionsMode, @UserIdInt int userId) {
+ @NonNull PackageInstalledParams params, @UserIdInt int userId) {
Objects.requireNonNull(pkg, "pkg");
- Objects.requireNonNull(grantedPermissions, "grantedPermissions");
- Objects.requireNonNull(allowlistedRestrictedPermissions,
- "allowlistedRestrictedPermissions");
+ Objects.requireNonNull(params, "params");
Preconditions.checkArgumentNonNegative(userId, "userId");
- onPackageInstalledInternal(pkg, grantedPermissions, allowlistedRestrictedPermissions,
- autoRevokePermissionsMode, userId);
+ onPackageInstalledInternal(pkg, params, userId);
}
@Override
@@ -5430,11 +5427,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
- public void onPackageStateRemoved(@NonNull String packageName, int appId,
- @Nullable AndroidPackage pkg, @NonNull List<AndroidPackage> sharedUserPkgs) {
- Objects.requireNonNull(packageName);
- Objects.requireNonNull(sharedUserPkgs);
- onPackageStateRemovedInternal(packageName, appId, pkg, sharedUserPkgs);
+ public void onPackageUninstalled(@NonNull String packageName, int appId,
+ @Nullable AndroidPackage pkg, @NonNull List<AndroidPackage> sharedUserPkgs,
+ @UserIdInt int userId) {
+ Objects.requireNonNull(packageName, "packageName");
+ Objects.requireNonNull(sharedUserPkgs, "sharedUserPkgs");
+ Preconditions.checkArgumentNonNegative(userId, "userId");
+ onPackageUninstalledInternal(packageName, appId, pkg, sharedUserPkgs, userId);
}
@Override
@@ -5467,6 +5466,32 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
+ /**
+ * Callbacks invoked when interesting actions have been taken on a permission.
+ * <p>
+ * NOTE: The current arguments are merely to support the existing use cases. This
+ * needs to be properly thought out with appropriate arguments for each of the
+ * callback methods.
+ */
+ private static class PermissionCallback {
+ public void onGidsChanged(@AppIdInt int appId, @UserIdInt int userId) {}
+ public void onPermissionChanged() {}
+ public void onPermissionGranted(int uid, @UserIdInt int userId) {}
+ public void onInstallPermissionGranted() {}
+ public void onPermissionRevoked(int uid, @UserIdInt int userId, String reason) {}
+ public void onInstallPermissionRevoked() {}
+ public void onPermissionUpdated(@UserIdInt int[] updatedUserIds, boolean sync) {}
+ public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
+ int uid) {
+ onPermissionUpdated(updatedUserIds, sync);
+ }
+ public void onPermissionRemoved() {}
+ public void onInstallPermissionUpdated() {}
+ public void onInstallPermissionUpdatedNotifyListener(int uid) {
+ onInstallPermissionUpdated();
+ }
+ }
+
private static final class OnPermissionChangeListeners extends Handler {
private static final int MSG_ON_PERMISSIONS_CHANGED = 1;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 457fe36ca2b8..f924651f1051 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -16,17 +16,19 @@
package com.android.server.pm.permission;
-import android.annotation.AppIdInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.AppOpsManager;
import android.content.pm.PermissionInfo;
import android.permission.PermissionManagerInternal;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
@@ -140,41 +142,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
@NonNull Consumer<Boolean> callback);
}
- /**
- * Callbacks invoked when interesting actions have been taken on a permission.
- * <p>
- * NOTE: The current arguments are merely to support the existing use cases. This
- * needs to be properly thought out with appropriate arguments for each of the
- * callback methods.
- */
- public static class PermissionCallback {
- public void onGidsChanged(@AppIdInt int appId, @UserIdInt int userId) {
- }
- public void onPermissionChanged() {
- }
- public void onPermissionGranted(int uid, @UserIdInt int userId) {
- }
- public void onInstallPermissionGranted() {
- }
- public void onPermissionRevoked(int uid, @UserIdInt int userId, String reason) {
- }
- public void onInstallPermissionRevoked() {
- }
- public void onPermissionUpdated(@UserIdInt int[] updatedUserIds, boolean sync) {
- }
- public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
- int uid) {
- onPermissionUpdated(updatedUserIds, sync);
- }
- public void onPermissionRemoved() {
- }
- public void onInstallPermissionUpdated() {
- }
- public void onInstallPermissionUpdatedNotifyListener(int uid) {
- onInstallPermissionUpdated();
- }
- }
-
public abstract void systemReady();
/**
@@ -189,22 +156,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
@UserIdInt int userId);
/**
- * Update permissions when a package changed.
- *
- * <p><ol>
- * <li>Reconsider the ownership of permission</li>
- * <li>Update the state (grant, flags) of the permissions</li>
- * </ol>
- *
- * @param packageName The package that is updated
- * @param pkg The package that is updated, or {@code null} if package is deleted
- * @param allPackages All currently known packages
- * @param callback Callback to call after permission changes
- */
- public abstract void updatePermissions(@NonNull String packageName,
- @Nullable AndroidPackage pkg);
-
- /**
* Update all permissions for all apps.
*
* <p><ol>
@@ -489,19 +440,15 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
@Nullable AndroidPackage oldPkg);
/**
- * Callback when a package has been installed for certain users.
+ * Callback when a package has been installed for a user.
*
* @param pkg the installed package
- * @param grantedPermissions the permissions to be granted
- * @param allowlistedRestrictedPermissions the restricted permissions to be allowlisted
- * @param autoRevokePermissionsMode the auto revoke permissions mode for this package
+ * @param params the parameters passed in for package installation
* @param userId the user ID this package is installed for
*/
//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public abstract void onPackageInstalled(@NonNull AndroidPackage pkg,
- @NonNull List<String> grantedPermissions,
- @NonNull List<String> allowlistedRestrictedPermissions,
- int autoRevokePermissionsMode, @UserIdInt int userId);
+ @NonNull PackageInstalledParams params, @UserIdInt int userId);
/**
* Callback when a package has been removed.
@@ -512,16 +459,23 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract void onPackageRemoved(@NonNull AndroidPackage pkg);
/**
- * Callback when the state for a package has been removed.
+ * Callback when a package has been uninstalled.
+ * <p>
+ * The package may have been fully removed from the system, or only marked as uninstalled for
+ * this user but still instlaled for other users.
+ *
+ * TODO: Pass PackageState instead.
*
- * @param packageName the name of the removed package
- * @param appId the app ID of the removed package
- * @param pkg the removed package, or {@code null} if unavailable
+ * @param packageName the name of the uninstalled package
+ * @param appId the app ID of the uninstalled package
+ * @param pkg the uninstalled package, or {@code null} if unavailable
* @param sharedUserPkgs the packages that are in the same shared user
+ * @param userId the user ID the package is uninstalled for
*/
//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
- public abstract void onPackageStateRemoved(@NonNull String packageName, int appId,
- @Nullable AndroidPackage pkg, @NonNull List<AndroidPackage> sharedUserPkgs);
+ public abstract void onPackageUninstalled(@NonNull String packageName, int appId,
+ @Nullable AndroidPackage pkg, @NonNull List<AndroidPackage> sharedUserPkgs,
+ @UserIdInt int userId);
/**
* Check whether a permission can be propagated to instant app.
@@ -530,4 +484,132 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
* @return whether the permission can be propagated
*/
public abstract boolean canPropagatePermissionToInstantApp(@NonNull String permissionName);
+
+ /**
+ * The permission-related parameters passed in for package installation.
+ *
+ * @see android.content.pm.PackageInstaller.SessionParams
+ */
+ //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+ public static final class PackageInstalledParams {
+ /**
+ * A static instance whose parameters are all in their default state.
+ */
+ public static final PackageInstalledParams DEFAULT = new Builder().build();
+
+ @NonNull
+ private final List<String> mGrantedPermissions;
+ @NonNull
+ private final List<String> mAllowlistedRestrictedPermissions;
+ @NonNull
+ private final int mAutoRevokePermissionsMode;
+
+ private PackageInstalledParams(@NonNull List<String> grantedPermissions,
+ @NonNull List<String> allowlistedRestrictedPermissions,
+ int autoRevokePermissionsMode) {
+ mGrantedPermissions = grantedPermissions;
+ mAllowlistedRestrictedPermissions = allowlistedRestrictedPermissions;
+ mAutoRevokePermissionsMode = autoRevokePermissionsMode;
+ }
+
+ /**
+ * Get the permissions to be granted.
+ *
+ * @return the permissions to be granted
+ */
+ @NonNull
+ public List<String> getGrantedPermissions() {
+ return mGrantedPermissions;
+ }
+
+ /**
+ * Get the restricted permissions to be allowlisted.
+ *
+ * @return the restricted permissions to be allowlisted
+ */
+ @NonNull
+ public List<String> getAllowlistedRestrictedPermissions() {
+ return mAllowlistedRestrictedPermissions;
+ }
+
+ /**
+ * Get the mode for auto revoking permissions.
+ *
+ * @return the mode for auto revoking permissions
+ */
+ public int getAutoRevokePermissionsMode() {
+ return mAutoRevokePermissionsMode;
+ }
+
+ /**
+ * Builder class for {@link PackageInstalledParams}.
+ */
+ public static final class Builder {
+ @NonNull
+ private List<String> mGrantedPermissions = Collections.emptyList();
+ @NonNull
+ private List<String> mAllowlistedRestrictedPermissions = Collections.emptyList();
+ @NonNull
+ private int mAutoRevokePermissionsMode = AppOpsManager.MODE_DEFAULT;
+
+ /**
+ * Set the permissions to be granted.
+ *
+ * @param grantedPermissions the permissions to be granted
+ *
+ * @see android.content.pm.PackageInstaller.SessionParams#setGrantedRuntimePermissions(
+ * java.lang.String[])
+ */
+ public void setGrantedPermissions(@NonNull List<String> grantedPermissions) {
+ Objects.requireNonNull(grantedPermissions);
+ mGrantedPermissions = new ArrayList<>(grantedPermissions);
+ }
+
+ /**
+ * Set the restricted permissions to be allowlisted.
+ * <p>
+ * Permissions that are not restricted are ignored, so one can just pass in all
+ * requested permissions of a package to get all its restricted permissions allowlisted.
+ *
+ * @param allowlistedRestrictedPermissions the restricted permissions to be allowlisted
+ *
+ * @see android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)
+ */
+ public void setAllowlistedRestrictedPermissions(
+ @NonNull List<String> allowlistedRestrictedPermissions) {
+ Objects.requireNonNull(mGrantedPermissions);
+ mAllowlistedRestrictedPermissions = new ArrayList<>(
+ allowlistedRestrictedPermissions);
+ }
+
+ /**
+ * Set the mode for auto revoking permissions.
+ * <p>
+ * {@link AppOpsManager#MODE_ALLOWED} means the system is allowed to auto revoke
+ * permissions from this package, and {@link AppOpsManager#MODE_IGNORED} means this
+ * package should be ignored when auto revoking permissions.
+ * {@link AppOpsManager#MODE_DEFAULT} means no changes will be made to the auto revoke
+ * mode of this package.
+ *
+ * @param autoRevokePermissionsMode the mode for auto revoking permissions
+ *
+ * @see android.content.pm.PackageInstaller.SessionParams#setAutoRevokePermissionsMode(
+ * boolean)
+ */
+ public void setAutoRevokePermissionsMode(int autoRevokePermissionsMode) {
+ mAutoRevokePermissionsMode = autoRevokePermissionsMode;
+ }
+
+ /**
+ * Build a new instance of {@link PackageInstalledParams}.
+ *
+ * @return the {@link PackageInstalledParams} built
+ */
+ @NonNull
+ public PackageInstalledParams build() {
+ return new PackageInstalledParams(mGrantedPermissions,
+ mAllowlistedRestrictedPermissions, mAutoRevokePermissionsMode);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index 1883f4e4e86c..ccd4e0ffa3e7 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -29,6 +29,7 @@ import android.os.PowerSaveState;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
import android.util.Slog;
import android.view.accessibility.AccessibilityManager;
@@ -1031,90 +1032,92 @@ public class BatterySaverPolicy extends ContentObserver {
}
public void dump(PrintWriter pw) {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+
synchronized (mLock) {
- pw.println();
- mBatterySavingStats.dump(pw, "");
-
- pw.println();
- pw.println("Battery saver policy (*NOTE* they only apply when battery saver is ON):");
- pw.println(" Settings: " + Settings.Global.BATTERY_SAVER_CONSTANTS);
- pw.println(" value: " + mSettings);
- pw.println(" Settings: " + mDeviceSpecificSettingsSource);
- pw.println(" value: " + mDeviceSpecificSettings);
-
- pw.println(" Adaptive Settings: " + Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS);
- pw.println(" value: " + mAdaptiveSettings);
- pw.println(" Adaptive Device Specific Settings: "
+ ipw.println();
+ mBatterySavingStats.dump(ipw);
+
+ ipw.println();
+ ipw.println("Battery saver policy (*NOTE* they only apply when battery saver is ON):");
+ ipw.increaseIndent();
+ ipw.println("Settings: " + Settings.Global.BATTERY_SAVER_CONSTANTS);
+ ipw.increaseIndent();
+ ipw.println("value: " + mSettings);
+ ipw.decreaseIndent();
+ ipw.println("Settings: " + mDeviceSpecificSettingsSource);
+ ipw.increaseIndent();
+ ipw.println("value: " + mDeviceSpecificSettings);
+ ipw.decreaseIndent();
+
+ ipw.println("Adaptive Settings: " + Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS);
+ ipw.increaseIndent();
+ ipw.println("value: " + mAdaptiveSettings);
+ ipw.decreaseIndent();
+ ipw.println("Adaptive Device Specific Settings: "
+ Settings.Global.BATTERY_SAVER_ADAPTIVE_DEVICE_SPECIFIC_CONSTANTS);
- pw.println(" value: " + mAdaptiveDeviceSpecificSettings);
+ ipw.increaseIndent();
+ ipw.println("value: " + mAdaptiveDeviceSpecificSettings);
+ ipw.decreaseIndent();
+
+ ipw.println("mAccessibilityEnabled=" + mAccessibilityEnabled.get());
+ ipw.println("mAutomotiveProjectionActive=" + mAutomotiveProjectionActive.get());
+ ipw.println("mPolicyLevel=" + mPolicyLevel);
- pw.println(" mAccessibilityEnabled=" + mAccessibilityEnabled.get());
- pw.println(" mAutomotiveProjectionActive=" + mAutomotiveProjectionActive.get());
- pw.println(" mPolicyLevel=" + mPolicyLevel);
+ dumpPolicyLocked(ipw, "full", mFullPolicy);
+ dumpPolicyLocked(ipw, "default adaptive", mDefaultAdaptivePolicy);
+ dumpPolicyLocked(ipw, "current adaptive", mAdaptivePolicy);
+ dumpPolicyLocked(ipw, "effective", mEffectivePolicyRaw);
- dumpPolicyLocked(pw, " ", "full", mFullPolicy);
- dumpPolicyLocked(pw, " ", "default adaptive", mDefaultAdaptivePolicy);
- dumpPolicyLocked(pw, " ", "current adaptive", mAdaptivePolicy);
- dumpPolicyLocked(pw, " ", "effective", mEffectivePolicyRaw);
+ ipw.decreaseIndent();
}
}
- private void dumpPolicyLocked(PrintWriter pw, String indent, String label, Policy p) {
+ private void dumpPolicyLocked(IndentingPrintWriter pw, String label, Policy p) {
pw.println();
- pw.print(indent);
pw.println("Policy '" + label + "'");
- pw.print(indent);
- pw.println(" " + KEY_ADVERTISE_IS_ENABLED + "=" + p.advertiseIsEnabled);
- pw.print(indent);
- pw.println(" " + KEY_VIBRATION_DISABLED + "=" + p.disableVibration);
- pw.print(indent);
- pw.println(" " + KEY_ANIMATION_DISABLED + "=" + p.disableAnimation);
- pw.print(indent);
- pw.println(" " + KEY_FULLBACKUP_DEFERRED + "=" + p.deferFullBackup);
- pw.print(indent);
- pw.println(" " + KEY_KEYVALUE_DEFERRED + "=" + p.deferKeyValueBackup);
- pw.print(indent);
- pw.println(" " + KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !p.enableFirewall);
- pw.print(indent);
- pw.println(" " + KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !p.enableDataSaver);
- pw.print(indent);
- pw.println(" " + KEY_LAUNCH_BOOST_DISABLED + "=" + p.disableLaunchBoost);
- pw.println(
- " " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + !p.enableAdjustBrightness);
- pw.print(indent);
- pw.println(" " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + p.adjustBrightnessFactor);
- pw.print(indent);
- pw.println(" " + KEY_GPS_MODE + "=" + p.locationMode);
- pw.print(indent);
- pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY + "=" + p.forceAllAppsStandby);
- pw.print(indent);
- pw.println(" " + KEY_FORCE_BACKGROUND_CHECK + "=" + p.forceBackgroundCheck);
- pw.println(
- " " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + p.disableOptionalSensors);
- pw.print(indent);
- pw.println(" " + KEY_AOD_DISABLED + "=" + p.disableAod);
- pw.print(indent);
- pw.println(" " + KEY_SOUNDTRIGGER_DISABLED + "=" + p.disableSoundTrigger);
- pw.print(indent);
- pw.println(" " + KEY_QUICK_DOZE_ENABLED + "=" + p.enableQuickDoze);
- pw.print(indent);
- pw.println(" " + KEY_ENABLE_NIGHT_MODE + "=" + p.enableNightMode);
-
- pw.print(" Interactive File values:\n");
- dumpMap(pw, " ", p.filesForInteractive);
+ pw.increaseIndent();
+ pw.println(KEY_ADVERTISE_IS_ENABLED + "=" + p.advertiseIsEnabled);
+ pw.println(KEY_VIBRATION_DISABLED + "=" + p.disableVibration);
+ pw.println(KEY_ANIMATION_DISABLED + "=" + p.disableAnimation);
+ pw.println(KEY_FULLBACKUP_DEFERRED + "=" + p.deferFullBackup);
+ pw.println(KEY_KEYVALUE_DEFERRED + "=" + p.deferKeyValueBackup);
+ pw.println(KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !p.enableFirewall);
+ pw.println(KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !p.enableDataSaver);
+ pw.println(KEY_LAUNCH_BOOST_DISABLED + "=" + p.disableLaunchBoost);
+ pw.println(KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + !p.enableAdjustBrightness);
+ pw.println(KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + p.adjustBrightnessFactor);
+ pw.println(KEY_GPS_MODE + "=" + p.locationMode);
+ pw.println(KEY_FORCE_ALL_APPS_STANDBY + "=" + p.forceAllAppsStandby);
+ pw.println(KEY_FORCE_BACKGROUND_CHECK + "=" + p.forceBackgroundCheck);
+ pw.println(KEY_OPTIONAL_SENSORS_DISABLED + "=" + p.disableOptionalSensors);
+ pw.println(KEY_AOD_DISABLED + "=" + p.disableAod);
+ pw.println(KEY_SOUNDTRIGGER_DISABLED + "=" + p.disableSoundTrigger);
+ pw.println(KEY_QUICK_DOZE_ENABLED + "=" + p.enableQuickDoze);
+ pw.println(KEY_ENABLE_NIGHT_MODE + "=" + p.enableNightMode);
+
+ pw.println("Interactive File values:");
+ pw.increaseIndent();
+ dumpMap(pw, p.filesForInteractive);
+ pw.decreaseIndent();
pw.println();
- pw.print(" Noninteractive File values:\n");
- dumpMap(pw, " ", p.filesForNoninteractive);
+ pw.println("Noninteractive File values:");
+ pw.increaseIndent();
+ dumpMap(pw, p.filesForNoninteractive);
+ pw.decreaseIndent();
+
+ // Decrease from indent right after "Policy" line
+ pw.decreaseIndent();
}
- private void dumpMap(PrintWriter pw, String prefix, ArrayMap<String, String> map) {
+ private void dumpMap(PrintWriter pw, ArrayMap<String, String> map) {
if (map == null) {
+ pw.println("N/A");
return;
}
final int size = map.size();
for (int i = 0; i < size; i++) {
- pw.print(prefix);
pw.print(map.keyAt(i));
pw.print(": '");
pw.print(map.valueAt(i));
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index af14d84d12b8..21500f649099 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -34,6 +34,7 @@ import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -888,70 +889,75 @@ public class BatterySaverStateMachine {
}
public void dump(PrintWriter pw) {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+
+ ipw.println();
+ ipw.println("Battery saver state machine:");
+ ipw.increaseIndent();
synchronized (mLock) {
- pw.println();
- pw.println("Battery saver state machine:");
-
- pw.print(" Enabled=");
- pw.println(mBatterySaverController.isEnabled());
- pw.print(" full=");
- pw.println(mBatterySaverController.isFullEnabled());
- pw.print(" adaptive=");
- pw.print(mBatterySaverController.isAdaptiveEnabled());
+ ipw.print("Enabled=");
+ ipw.println(mBatterySaverController.isEnabled());
+ ipw.increaseIndent();
+ ipw.print("full=");
+ ipw.println(mBatterySaverController.isFullEnabled());
+ ipw.print("adaptive=");
+ ipw.print(mBatterySaverController.isAdaptiveEnabled());
if (mBatterySaverController.isAdaptiveEnabled()) {
- pw.print(" (advertise=");
- pw.print(
+ ipw.print(" (advertise=");
+ ipw.print(
mBatterySaverController.getBatterySaverPolicy().shouldAdvertiseIsEnabled());
- pw.print(")");
+ ipw.print(")");
}
- pw.println();
- pw.print(" mState=");
- pw.println(mState);
-
- pw.print(" mLastChangedIntReason=");
- pw.println(mLastChangedIntReason);
- pw.print(" mLastChangedStrReason=");
- pw.println(mLastChangedStrReason);
-
- pw.print(" mBootCompleted=");
- pw.println(mBootCompleted);
- pw.print(" mSettingsLoaded=");
- pw.println(mSettingsLoaded);
- pw.print(" mBatteryStatusSet=");
- pw.println(mBatteryStatusSet);
-
- pw.print(" mIsPowered=");
- pw.println(mIsPowered);
- pw.print(" mBatteryLevel=");
- pw.println(mBatteryLevel);
- pw.print(" mIsBatteryLevelLow=");
- pw.println(mIsBatteryLevelLow);
-
- pw.print(" mSettingAutomaticBatterySaver=");
- pw.println(mSettingAutomaticBatterySaver);
- pw.print(" mSettingBatterySaverEnabled=");
- pw.println(mSettingBatterySaverEnabled);
- pw.print(" mSettingBatterySaverEnabledSticky=");
- pw.println(mSettingBatterySaverEnabledSticky);
- pw.print(" mSettingBatterySaverStickyAutoDisableEnabled=");
- pw.println(mSettingBatterySaverStickyAutoDisableEnabled);
- pw.print(" mSettingBatterySaverStickyAutoDisableThreshold=");
- pw.println(mSettingBatterySaverStickyAutoDisableThreshold);
- pw.print(" mSettingBatterySaverTriggerThreshold=");
- pw.println(mSettingBatterySaverTriggerThreshold);
- pw.print(" mBatterySaverStickyBehaviourDisabled=");
- pw.println(mBatterySaverStickyBehaviourDisabled);
-
- pw.print(" mDynamicPowerSavingsDefaultDisableThreshold=");
- pw.println(mDynamicPowerSavingsDefaultDisableThreshold);
- pw.print(" mDynamicPowerSavingsDisableThreshold=");
- pw.println(mDynamicPowerSavingsDisableThreshold);
- pw.print(" mDynamicPowerSavingsEnableBatterySaver=");
- pw.println(mDynamicPowerSavingsEnableBatterySaver);
-
- pw.print(" mLastAdaptiveBatterySaverChangedExternallyElapsed=");
- pw.println(mLastAdaptiveBatterySaverChangedExternallyElapsed);
+ ipw.decreaseIndent();
+ ipw.println();
+ ipw.print("mState=");
+ ipw.println(mState);
+
+ ipw.print("mLastChangedIntReason=");
+ ipw.println(mLastChangedIntReason);
+ ipw.print("mLastChangedStrReason=");
+ ipw.println(mLastChangedStrReason);
+
+ ipw.print("mBootCompleted=");
+ ipw.println(mBootCompleted);
+ ipw.print("mSettingsLoaded=");
+ ipw.println(mSettingsLoaded);
+ ipw.print("mBatteryStatusSet=");
+ ipw.println(mBatteryStatusSet);
+
+ ipw.print("mIsPowered=");
+ ipw.println(mIsPowered);
+ ipw.print("mBatteryLevel=");
+ ipw.println(mBatteryLevel);
+ ipw.print("mIsBatteryLevelLow=");
+ ipw.println(mIsBatteryLevelLow);
+
+ ipw.print("mSettingAutomaticBatterySaver=");
+ ipw.println(mSettingAutomaticBatterySaver);
+ ipw.print("mSettingBatterySaverEnabled=");
+ ipw.println(mSettingBatterySaverEnabled);
+ ipw.print("mSettingBatterySaverEnabledSticky=");
+ ipw.println(mSettingBatterySaverEnabledSticky);
+ ipw.print("mSettingBatterySaverStickyAutoDisableEnabled=");
+ ipw.println(mSettingBatterySaverStickyAutoDisableEnabled);
+ ipw.print("mSettingBatterySaverStickyAutoDisableThreshold=");
+ ipw.println(mSettingBatterySaverStickyAutoDisableThreshold);
+ ipw.print("mSettingBatterySaverTriggerThreshold=");
+ ipw.println(mSettingBatterySaverTriggerThreshold);
+ ipw.print("mBatterySaverStickyBehaviourDisabled=");
+ ipw.println(mBatterySaverStickyBehaviourDisabled);
+
+ ipw.print("mDynamicPowerSavingsDefaultDisableThreshold=");
+ ipw.println(mDynamicPowerSavingsDefaultDisableThreshold);
+ ipw.print("mDynamicPowerSavingsDisableThreshold=");
+ ipw.println(mDynamicPowerSavingsDisableThreshold);
+ ipw.print("mDynamicPowerSavingsEnableBatterySaver=");
+ ipw.println(mDynamicPowerSavingsEnableBatterySaver);
+
+ ipw.print("mLastAdaptiveBatterySaverChangedExternallyElapsed=");
+ ipw.println(mLastAdaptiveBatterySaverChangedExternallyElapsed);
}
+ ipw.decreaseIndent();
}
public void dumpProto(ProtoOutputStream proto, long tag) {
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
index 05695d919910..a7be2677cf23 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
@@ -17,6 +17,7 @@ package com.android.server.power.batterysaver;
import android.os.BatteryManagerInternal;
import android.os.SystemClock;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -26,7 +27,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
-import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -391,18 +391,15 @@ public class BatterySavingStats {
stat.endTime = 0;
}
- public void dump(PrintWriter pw, String indent) {
- synchronized (mLock) {
- pw.print(indent);
- pw.println("Battery saving stats:");
-
- indent = indent + " ";
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("Battery saving stats:");
+ pw.increaseIndent();
+ synchronized (mLock) {
final long now = System.currentTimeMillis();
final long nowElapsed = injectCurrentTime();
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
- pw.print(indent);
pw.print("Battery Saver is currently: ");
switch (BatterySaverState.fromIndex(mCurrentState)) {
case BatterySaverState.OFF:
@@ -416,9 +413,8 @@ public class BatterySavingStats {
break;
}
+ pw.increaseIndent();
if (mLastBatterySaverEnabledTime > 0) {
- pw.print(indent);
- pw.print(" ");
pw.print("Last ON time: ");
pw.print(sdf.format(new Date(now - nowElapsed + mLastBatterySaverEnabledTime)));
pw.print(" ");
@@ -427,8 +423,6 @@ public class BatterySavingStats {
}
if (mLastBatterySaverDisabledTime > 0) {
- pw.print(indent);
- pw.print(" ");
pw.print("Last OFF time: ");
pw.print(sdf.format(new Date(now - nowElapsed + mLastBatterySaverDisabledTime)));
pw.print(" ");
@@ -436,14 +430,10 @@ public class BatterySavingStats {
pw.println();
}
- pw.print(indent);
- pw.print(" ");
pw.print("Times full enabled: ");
pw.println(mBatterySaverEnabledCount);
if (mLastAdaptiveBatterySaverEnabledTime > 0) {
- pw.print(indent);
- pw.print(" ");
pw.print("Last ADAPTIVE ON time: ");
pw.print(sdf.format(
new Date(now - nowElapsed + mLastAdaptiveBatterySaverEnabledTime)));
@@ -452,8 +442,6 @@ public class BatterySavingStats {
pw.println();
}
if (mLastAdaptiveBatterySaverDisabledTime > 0) {
- pw.print(indent);
- pw.print(" ");
pw.print("Last ADAPTIVE OFF time: ");
pw.print(sdf.format(
new Date(now - nowElapsed + mLastAdaptiveBatterySaverDisabledTime)));
@@ -461,39 +449,36 @@ public class BatterySavingStats {
TimeUtils.formatDuration(mLastAdaptiveBatterySaverDisabledTime, nowElapsed, pw);
pw.println();
}
- pw.print(indent);
- pw.print(" ");
pw.print("Times adaptive enabled: ");
pw.println(mAdaptiveBatterySaverEnabledCount);
+ pw.decreaseIndent();
pw.println();
- pw.print(indent);
pw.println("Drain stats:");
- pw.print(indent);
pw.println(" Battery saver OFF ON");
- dumpLineLocked(pw, indent, InteractiveState.NON_INTERACTIVE, "NonIntr",
+ dumpLineLocked(pw, InteractiveState.NON_INTERACTIVE, "NonIntr",
DozeState.NOT_DOZING, "NonDoze");
- dumpLineLocked(pw, indent, InteractiveState.INTERACTIVE, " Intr",
+ dumpLineLocked(pw, InteractiveState.INTERACTIVE, " Intr",
DozeState.NOT_DOZING, " ");
- dumpLineLocked(pw, indent, InteractiveState.NON_INTERACTIVE, "NonIntr",
+ dumpLineLocked(pw, InteractiveState.NON_INTERACTIVE, "NonIntr",
DozeState.DEEP, "Deep ");
- dumpLineLocked(pw, indent, InteractiveState.INTERACTIVE, " Intr",
+ dumpLineLocked(pw, InteractiveState.INTERACTIVE, " Intr",
DozeState.DEEP, " ");
- dumpLineLocked(pw, indent, InteractiveState.NON_INTERACTIVE, "NonIntr",
+ dumpLineLocked(pw, InteractiveState.NON_INTERACTIVE, "NonIntr",
DozeState.LIGHT, "Light ");
- dumpLineLocked(pw, indent, InteractiveState.INTERACTIVE, " Intr",
+ dumpLineLocked(pw, InteractiveState.INTERACTIVE, " Intr",
DozeState.LIGHT, " ");
}
+ pw.decreaseIndent();
}
- private void dumpLineLocked(PrintWriter pw, String indent,
+ private void dumpLineLocked(IndentingPrintWriter pw,
int interactiveState, String interactiveLabel,
int dozeState, String dozeLabel) {
- pw.print(indent);
pw.print(dozeLabel);
pw.print(" ");
pw.print(interactiveLabel);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
index 5b6de0518999..4f3f9dce8adb 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
@@ -16,6 +16,8 @@
package com.android.server.timedetector;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;
import android.annotation.NonNull;
@@ -30,6 +32,9 @@ import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Slog;
+import com.android.internal.R;
+import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+
import java.time.Instant;
import java.util.Objects;
@@ -50,6 +55,13 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
/**
+ * By default telephony and network only suggestions are accepted and telephony takes
+ * precedence over network.
+ */
+ private static final @Origin int[] DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES =
+ { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
+
+ /**
* If a newly calculated system clock time and the current system clock time differs by this or
* more the system clock will actually be updated. Used to prevent the system clock being set
* for only minor differences.
@@ -76,14 +88,7 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
SystemProperties.getInt("ro.sys.time_detector_update_diff",
SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
- // TODO(b/172230856): Obtain these values from configuration.
- String[] originStrings = { "telephony", "network" };
- int[] origins = new int[originStrings.length];
- for (int i = 0; i < originStrings.length; i++) {
- int origin = stringToOrigin(originStrings[i]);
- origins[i] = origin;
- }
- mOriginPriorities = origins;
+ mOriginPriorities = getOriginPriorities(context);
}
@Override
@@ -106,7 +111,7 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
}
@Override
- public int[] getAutoOriginPriorities() {
+ public int[] autoOriginPriorities() {
return mOriginPriorities;
}
@@ -145,4 +150,20 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
Slog.wtf(TAG, "WakeLock " + mWakeLock + " not held");
}
}
+
+ private static int[] getOriginPriorities(@NonNull Context context) {
+ String[] originStrings =
+ context.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
+ if (originStrings.length == 0) {
+ return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
+ } else {
+ int[] origins = new int[originStrings.length];
+ for (int i = 0; i < originStrings.length; i++) {
+ int origin = stringToOrigin(originStrings[i]);
+ origins[i] = origin;
+ }
+
+ return origins;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index d8cada55781c..b5d49cfbe9c8 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -18,6 +18,8 @@ package com.android.server.timedetector;
import static com.android.server.timedetector.TimeDetectorStrategy.originToString;
+import static java.util.stream.Collectors.joining;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
@@ -140,7 +142,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
* Returns the order to look at time suggestions when automatically detecting time.
* See {@code #ORIGIN_} constants
*/
- @Origin int[] getAutoOriginPriorities();
+ @Origin int[] autoOriginPriorities();
/** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
void acquireWakeLock();
@@ -252,6 +254,14 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
ipw.println("mCallback.systemClockMillis()=" + mCallback.systemClockMillis());
ipw.println("mCallback.systemClockUpdateThresholdMillis()="
+ mCallback.systemClockUpdateThresholdMillis());
+ ipw.printf("mCallback.autoTimeLowerBound()=%s(%s)\n",
+ mCallback.autoTimeLowerBound(),
+ mCallback.autoTimeLowerBound().toEpochMilli());
+ String priorities =
+ Arrays.stream(mCallback.autoOriginPriorities())
+ .mapToObj(TimeDetectorStrategy::originToString)
+ .collect(joining(",", "[", "]"));
+ ipw.println("mCallback.autoOriginPriorities()=" + priorities);
ipw.println("Time change log:");
ipw.increaseIndent(); // level 2
@@ -353,7 +363,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
// Try the different origins one at a time.
- int[] originPriorities = mCallback.getAutoOriginPriorities();
+ int[] originPriorities = mCallback.autoOriginPriorities();
for (int origin : originPriorities) {
TimestampedValue<Long> newUtcTime = null;
String cause = null;
diff --git a/services/core/java/com/android/server/tv/TEST_MAPPING b/services/core/java/com/android/server/tv/TEST_MAPPING
new file mode 100644
index 000000000000..f718f909fecb
--- /dev/null
+++ b/services/core/java/com/android/server/tv/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "cts/tests/tests/tv"
+ }
+ ]
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 510893b2940b..608012e4a310 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -768,6 +768,7 @@ public final class TvInputManagerService extends SystemService {
SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
if (sessionState == null) {
+ Slog.e(TAG, "sessionState null, no more remove session action!");
return;
}
@@ -2525,8 +2526,16 @@ public final class TvInputManagerService extends SystemService {
ClientState clientState = userState.clientStateMap.get(clientToken);
if (clientState != null) {
while (clientState.sessionTokens.size() > 0) {
+ IBinder sessionToken = clientState.sessionTokens.get(0);
releaseSessionLocked(
- clientState.sessionTokens.get(0), Process.SYSTEM_UID, userId);
+ sessionToken, Process.SYSTEM_UID, userId);
+ // the releaseSessionLocked function may return before the sessionToken
+ // is removed if the related sessionState is null. So need to check again
+ // to avoid death curculation.
+ if (clientState.sessionTokens.contains(sessionToken)) {
+ Slog.d(TAG, "remove sessionToken " + sessionToken + " for " + clientToken);
+ clientState.sessionTokens.remove(sessionToken);
+ }
}
}
clientToken = null;
diff --git a/services/core/java/com/android/server/utils/Snappable.java b/services/core/java/com/android/server/utils/Snappable.java
new file mode 100644
index 000000000000..9b9460b8f757
--- /dev/null
+++ b/services/core/java/com/android/server/utils/Snappable.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import android.annotation.NonNull;
+
+/**
+ * A class that implements Snappable can generate a read-only copy its instances. A
+ * snapshot is like a clone except that it is only required to support read-only class
+ * methods. Snapshots are immutable. Attempts to modify the state of a snapshot throw
+ * {@link UnsupporteOperationException}.
+ * @param <T> The type returned by the snapshot() method.
+ */
+public interface Snappable<T> {
+
+ /**
+ * Create an immutable copy of the object, suitable for read-only methods. A snapshot
+ * is free to omit state that is only needed for mutating methods.
+ */
+ @NonNull T snapshot();
+}
diff --git a/services/core/java/com/android/server/utils/Snapshots.java b/services/core/java/com/android/server/utils/Snapshots.java
new file mode 100644
index 000000000000..33b2bd48d802
--- /dev/null
+++ b/services/core/java/com/android/server/utils/Snapshots.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import android.annotation.NonNull;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.SparseSetArray;
+
+/**
+ * A collection of useful methods for manipulating Snapshot classes. This is similar to
+ * java.util.Objects or java.util.Arrays.
+ */
+public class Snapshots {
+
+ /**
+ * Return the snapshot of an object, if the object extends {@link Snapper}, or the object
+ * itself.
+ * @param o The object to be copied
+ * @return A snapshot of the object, if the object extends {@link Snapper}
+ */
+ public static <T> T maybeSnapshot(T o) {
+ if (o instanceof Snappable) {
+ return ((Snappable<T>) o).snapshot();
+ } else {
+ return o;
+ }
+ }
+
+ /**
+ * Copy a SparseArray in a manner suitable for a snapshot. The destination must be
+ * empty. This is not a snapshot because the elements are copied by reference even if
+ * they are {@link Snappable}.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array
+ */
+ public <E> void copy(@NonNull SparseArray<E> dst, @NonNull SparseArray<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("copy destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ dst.put(src.keyAt(i), src.valueAt(i));
+ }
+ }
+
+ /**
+ * Copy a SparseSetArray in a manner suitable for a snapshot. The destination must be
+ * empty. This is not a snapshot because the elements are copied by reference even if
+ * they are {@link Snappable}.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array
+ */
+ public static <E> void copy(@NonNull SparseSetArray<E> dst, @NonNull SparseSetArray<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("copy destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ final int size = src.sizeAt(i);
+ for (int j = 0; j < size; j++) {
+ dst.add(src.keyAt(i), src.valueAt(i, j));
+ }
+ }
+ }
+
+ /**
+ * Make <dst> a snapshot of <src> .
+ * @param dst The destination array. It must be empty.
+ * @param src The source array
+ */
+ public void snapshot(@NonNull SparseIntArray dst, @NonNull SparseIntArray src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ dst.put(src.keyAt(i), src.valueAt(i));
+ }
+ }
+
+ /**
+ * Make <dst> a "snapshot" of <src>. <dst> mst be empty. The destination is just a
+ * copy of the source except that if the source elements implement Snappable, then
+ * the elements in the destination will be snapshots of elements from the source.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array
+ */
+ public static <E extends Snappable<E>> void snapshot(@NonNull SparseArray<E> dst,
+ @NonNull SparseArray<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ dst.put(src.keyAt(i), src.valueAt(i).snapshot());
+ }
+ }
+
+ /**
+ * Make <dst> a "snapshot" of <src>. <dst> mst be empty. The destination is a
+ * copy of the source except that snapshots are taken of the elements.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array
+ */
+ public static <E extends Snappable<E>> void snapshot(@NonNull SparseSetArray<E> dst,
+ @NonNull SparseSetArray<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ final int size = src.sizeAt(i);
+ for (int j = 0; j < size; j++) {
+ dst.add(src.keyAt(i), src.valueAt(i, j).snapshot());
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/utils/WatchableImpl.java b/services/core/java/com/android/server/utils/WatchableImpl.java
index 94ab1d49807f..16400b186ab0 100644
--- a/services/core/java/com/android/server/utils/WatchableImpl.java
+++ b/services/core/java/com/android/server/utils/WatchableImpl.java
@@ -19,11 +19,15 @@ package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.ArrayList;
import java.util.Objects;
/**
- * A concrete implementation of {@link Watchable}
+ * A concrete implementation of {@link Watchable}. This includes one commonly needed feature:
+ * the Watchable may be sealed, so that it throws an {@link IllegalStateException} if
+ * a change is detected.
*/
public class WatchableImpl implements Watchable {
/**
@@ -78,10 +82,37 @@ public class WatchableImpl implements Watchable {
@Override
public void dispatchChange(@Nullable Watchable what) {
synchronized (mObservers) {
+ if (mSealed) {
+ throw new IllegalStateException("attempt to change a sealed object");
+ }
final int end = mObservers.size();
for (int i = 0; i < end; i++) {
mObservers.get(i).onChange(what);
}
}
}
+
+ /**
+ * True if the object is sealed.
+ */
+ @GuardedBy("mObservers")
+ private boolean mSealed = false;
+
+ /**
+ * Freeze the {@link Watchable}.
+ **/
+ public void seal() {
+ synchronized (mObservers) {
+ mSealed = true;
+ }
+ }
+
+ /**
+ * Return the sealed state.
+ */
+ public boolean isFrozen() {
+ synchronized (mObservers) {
+ return mSealed;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/utils/WatchedArrayMap.java b/services/core/java/com/android/server/utils/WatchedArrayMap.java
index 7b3298086aba..e8065f140af7 100644
--- a/services/core/java/com/android/server/utils/WatchedArrayMap.java
+++ b/services/core/java/com/android/server/utils/WatchedArrayMap.java
@@ -18,9 +18,7 @@ package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
-
import android.util.ArrayMap;
-import android.util.Log;
import java.util.Collection;
import java.util.Collections;
@@ -31,14 +29,17 @@ import java.util.Set;
* WatchedArrayMap is an {@link android.util.ArrayMap} that can report changes to itself. If its
* values are {@link Watchable} then the WatchedArrayMap will also report changes to the values.
* A {@link Watchable} is notified only once, no matter how many times it is stored in the array.
+ * @param <K> The key type.
+ * @param <V> The value type.
*/
-public class WatchedArrayMap<K, V> extends WatchableImpl implements Map<K, V> {
+public class WatchedArrayMap<K, V> extends WatchableImpl
+ implements Map<K, V>, Snappable {
// The storage
private final ArrayMap<K, V> mStorage;
// If true, the array is watching its children
- private boolean mWatching = false;
+ private volatile boolean mWatching = false;
// The local observer
private final Watcher mObserver = new Watcher() {
@@ -386,4 +387,38 @@ public class WatchedArrayMap<K, V> extends WatchableImpl implements Map<K, V> {
onChanged();
return result;
}
+
+ /**
+ * Create a copy of the array. If the element is a subclass of Snapper then the copy
+ * contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The returned snapshot is immutable.
+ * @return A new array whose elements are the elements of <this>.
+ */
+ public WatchedArrayMap<K, V> snapshot() {
+ WatchedArrayMap<K, V> l = new WatchedArrayMap<>();
+ snapshot(l, this);
+ return l;
+ }
+
+ /**
+ * Make the destination a copy of the source. If the element is a subclass of Snapper then the
+ * copy contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The destination must be initially empty. Upon return, the destination is
+ * immutable.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array. It is not modified.
+ */
+ public static <K, V> void snapshot(@NonNull WatchedArrayMap<K, V> dst,
+ @NonNull WatchedArrayMap<K, V> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ final V val = Snapshots.maybeSnapshot(src.valueAt(i));
+ final K key = src.keyAt(i);
+ dst.put(key, val);
+ }
+ dst.seal();
+ }
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseArray.java b/services/core/java/com/android/server/utils/WatchedSparseArray.java
index 4d43b682e113..6797c6eb7801 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseArray.java
@@ -18,7 +18,6 @@ package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
-
import android.util.SparseArray;
import java.util.ArrayList;
@@ -28,14 +27,16 @@ import java.util.ArrayList;
* array registers with the {@link Watchable}. The array registers only once with each
* {@link Watchable} no matter how many times the {@link Watchable} is stored in the
* array.
+ * @param <E> The element type, stored in the array.
*/
-public class WatchedSparseArray<E> extends WatchableImpl {
+public class WatchedSparseArray<E> extends WatchableImpl
+ implements Snappable {
// The storage
private final SparseArray<E> mStorage;
// If true, the array is watching its children
- private boolean mWatching = false;
+ private volatile boolean mWatching = false;
// The local observer
private final Watcher mObserver = new Watcher() {
@@ -398,4 +399,39 @@ public class WatchedSparseArray<E> extends WatchableImpl {
public String toString() {
return mStorage.toString();
}
+
+ /**
+ * Create a copy of the array. If the element is a subclass of Snapper then the copy
+ * contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The returned snapshot is immutable.
+ * @return A new array whose elements are the elements of <this>.
+ */
+ public WatchedSparseArray<E> snapshot() {
+ WatchedSparseArray<E> l = new WatchedSparseArray<>();
+ snapshot(l, this);
+ return l;
+ }
+
+ /**
+ * Make the destination a copy of the source. If the element is a subclass of Snapper then the
+ * copy contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The destination must be initially empty. Upon return, the destination is
+ * immutable.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array. It is not modified.
+ */
+ public static <E> void snapshot(@NonNull WatchedSparseArray<E> dst,
+ @NonNull WatchedSparseArray<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ final E val = Snapshots.maybeSnapshot(src.valueAt(i));
+ final int key = src.keyAt(i);
+ dst.put(key, val);
+ }
+ dst.seal();
+ }
+
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
index edf7d27b61dd..b845eea168a5 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
@@ -17,21 +17,20 @@
package com.android.server.utils;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-
import android.util.SparseBooleanArray;
/**
* A watched variant of SparseBooleanArray. Changes to the array are notified to
* registered {@link Watcher}s.
*/
-public class WatchedSparseBooleanArray extends WatchableImpl {
+public class WatchedSparseBooleanArray extends WatchableImpl
+ implements Snappable {
// The storage
private final SparseBooleanArray mStorage;
// A private convenience function
- private void dispatchChange() {
+ private void onChanged() {
dispatchChange(this);
}
@@ -81,7 +80,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
*/
public void delete(int key) {
mStorage.delete(key);
- dispatchChange();
+ onChanged();
}
/**
@@ -91,7 +90,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
*/
public void removeAt(int index) {
mStorage.removeAt(index);
- dispatchChange();
+ onChanged();
}
/**
@@ -102,7 +101,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
public void put(int key, boolean value) {
if (mStorage.get(key) != value) {
mStorage.put(key, value);
- dispatchChange();
+ onChanged();
}
}
@@ -164,7 +163,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
public void setValueAt(int index, boolean value) {
if (mStorage.valueAt(index) != value) {
mStorage.setValueAt(index, value);
- dispatchChange();
+ onChanged();
}
}
@@ -172,7 +171,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
public void setKeyAt(int index, int key) {
if (mStorage.keyAt(index) != key) {
mStorage.setKeyAt(index, key);
- dispatchChange();
+ onChanged();
}
}
@@ -202,7 +201,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
*/
public void clear() {
mStorage.clear();
- dispatchChange();
+ onChanged();
}
/**
@@ -211,7 +210,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
*/
public void append(int key, boolean value) {
mStorage.append(key, value);
- dispatchChange();
+ onChanged();
}
@Override
@@ -233,4 +232,30 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
public String toString() {
return mStorage.toString();
}
+
+ /**
+ * Create a snapshot. The snapshot does not include any {@link Watchable}
+ * information.
+ */
+ public WatchedSparseBooleanArray snapshot() {
+ WatchedSparseBooleanArray l = new WatchedSparseBooleanArray(this);
+ l.seal();
+ return l;
+ }
+
+ /**
+ * Make <this> a snapshot of the argument. Note that <this> is immutable when the
+ * method returns. <this> must be empty when the function is called.
+ * @param r The source array, which is copied into <this>
+ */
+ public void snapshot(@NonNull WatchedSparseBooleanArray r) {
+ if (size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = r.size();
+ for (int i = 0; i < end; i++) {
+ put(r.keyAt(i), r.valueAt(i));
+ }
+ seal();
+ }
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 583441207a36..c3d5874de609 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2846,8 +2846,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
if (!uidMatchPackage) {
return false; // callingPackage was faked.
}
- if (LocalServices.getService(DevicePolicyManagerInternal.class)
- .isDeviceOrProfileOwnerInCallingUser(callingPackage)) {
+ final DevicePolicyManagerInternal dpmi =
+ LocalServices.getService(DevicePolicyManagerInternal.class);
+ if (dpmi != null && dpmi.isDeviceOrProfileOwnerInCallingUser(callingPackage)) {
return true;
}
final int callingUserId = UserHandle.getCallingUserId();
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1336c81f18ed..2e55e92a4dcd 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1491,13 +1491,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
+ private ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage,
@Nullable String _launchedFromFeature, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo,
String _resultWho, int _reqCode, boolean _componentSpecified,
boolean _rootVoiceInteraction, ActivityTaskSupervisor supervisor,
- ActivityOptions options, ActivityRecord sourceRecord) {
+ ActivityOptions options, ActivityRecord sourceRecord, PersistableBundle persistentState,
+ TaskDescription _taskDescription, long _createTime) {
super(_service.mWindowManager, new Token(_intent).asBinder(), TYPE_APPLICATION, true,
null /* displayContent */, false /* ownerCanManageAppTokens */);
@@ -1652,6 +1653,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mHandoverLaunchDisplayId = options.getLaunchDisplayId();
mLaunchCookie = options.getLaunchCookie();
}
+
+ mPersistentState = persistentState;
+ taskDescription = _taskDescription;
+ if (_createTime > 0) {
+ createTime = _createTime;
+ }
}
/**
@@ -7544,18 +7551,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent +
" resolvedType=" + resolvedType);
}
- final ActivityRecord r = new ActivityRecord(service, null /* caller */,
- 0 /* launchedFromPid */, launchedFromUid, launchedFromPackage, launchedFromFeature,
- intent, resolvedType, aInfo, service.getConfiguration(), null /* resultTo */,
- null /* resultWho */, 0 /* reqCode */, componentSpecified,
- false /* rootVoiceInteraction */, taskSupervisor, null /* options */,
- null /* sourceRecord */);
-
- r.mPersistentState = persistentState;
- r.taskDescription = taskDescription;
- r.createTime = createTime;
-
- return r;
+ return new ActivityRecord.Builder(service)
+ .setLaunchedFromUid(launchedFromUid)
+ .setLaunchedFromPackage(launchedFromPackage)
+ .setLaunchedFromFeature(launchedFromFeature)
+ .setIntent(intent)
+ .setResolvedType(resolvedType)
+ .setActivityInfo(aInfo)
+ .setComponentSpecified(componentSpecified)
+ .setPersistentState(persistentState)
+ .setTaskDescription(taskDescription)
+ .setCreateTime(createTime)
+ .build();
}
private static boolean isInVrUiMode(Configuration config) {
@@ -7983,4 +7990,138 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
return false;
}
+
+ static class Builder {
+ private final ActivityTaskManagerService mAtmService;
+ private WindowProcessController mCallerApp;
+ private int mLaunchedFromPid;
+ private int mLaunchedFromUid;
+ private String mLaunchedFromPackage;
+ private String mLaunchedFromFeature;
+ private Intent mIntent;
+ private String mResolvedType;
+ private ActivityInfo mActivityInfo;
+ private Configuration mConfiguration;
+ private ActivityRecord mResultTo;
+ private String mResultWho;
+ private int mRequestCode;
+ private boolean mComponentSpecified;
+ private boolean mRootVoiceInteraction;
+ private ActivityOptions mOptions;
+ private ActivityRecord mSourceRecord;
+ private PersistableBundle mPersistentState;
+ private TaskDescription mTaskDescription;
+ private long mCreateTime;
+
+ Builder(ActivityTaskManagerService service) {
+ mAtmService = service;
+ }
+
+ Builder setCaller(@NonNull WindowProcessController caller) {
+ mCallerApp = caller;
+ return this;
+ }
+
+ Builder setLaunchedFromPid(int pid) {
+ mLaunchedFromPid = pid;
+ return this;
+ }
+
+ Builder setLaunchedFromUid(int uid) {
+ mLaunchedFromUid = uid;
+ return this;
+ }
+
+ Builder setLaunchedFromPackage(String fromPackage) {
+ mLaunchedFromPackage = fromPackage;
+ return this;
+ }
+
+ Builder setLaunchedFromFeature(String fromFeature) {
+ mLaunchedFromFeature = fromFeature;
+ return this;
+ }
+
+ Builder setIntent(Intent intent) {
+ mIntent = intent;
+ return this;
+ }
+
+ Builder setResolvedType(String resolvedType) {
+ mResolvedType = resolvedType;
+ return this;
+ }
+
+ Builder setActivityInfo(ActivityInfo activityInfo) {
+ mActivityInfo = activityInfo;
+ return this;
+ }
+
+ Builder setResultTo(ActivityRecord resultTo) {
+ mResultTo = resultTo;
+ return this;
+ }
+
+ Builder setResultWho(String resultWho) {
+ mResultWho = resultWho;
+ return this;
+ }
+
+ Builder setRequestCode(int reqCode) {
+ mRequestCode = reqCode;
+ return this;
+ }
+
+ Builder setComponentSpecified(boolean componentSpecified) {
+ mComponentSpecified = componentSpecified;
+ return this;
+ }
+
+ Builder setRootVoiceInteraction(boolean rootVoiceInteraction) {
+ mRootVoiceInteraction = rootVoiceInteraction;
+ return this;
+ }
+
+ Builder setActivityOptions(ActivityOptions options) {
+ mOptions = options;
+ return this;
+ }
+
+ Builder setConfiguration(Configuration config) {
+ mConfiguration = config;
+ return this;
+ }
+
+ Builder setSourceRecord(ActivityRecord source) {
+ mSourceRecord = source;
+ return this;
+ }
+
+ private Builder setPersistentState(PersistableBundle persistentState) {
+ mPersistentState = persistentState;
+ return this;
+ }
+
+ private Builder setTaskDescription(TaskDescription taskDescription) {
+ mTaskDescription = taskDescription;
+ return this;
+ }
+
+ private Builder setCreateTime(long createTime) {
+ mCreateTime = createTime;
+ return this;
+ }
+
+ ActivityRecord build() {
+ if (mConfiguration == null) {
+ mConfiguration = mAtmService.getConfiguration();
+ }
+ return new ActivityRecord(mAtmService, mCallerApp, mLaunchedFromPid,
+ mLaunchedFromUid, mLaunchedFromPackage, mLaunchedFromFeature, mIntent,
+ mResolvedType, mActivityInfo, mConfiguration, mResultTo, mResultWho,
+ mRequestCode, mComponentSpecified, mRootVoiceInteraction,
+ mAtmService.mTaskSupervisor, mOptions, mSourceRecord, mPersistentState,
+ mTaskDescription, mCreateTime);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 0bea25174f06..1ff3a3fb1d35 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1161,12 +1161,25 @@ class ActivityStarter {
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
}
+ final ActivityRecord r = new ActivityRecord.Builder(mService)
+ .setCaller(callerApp)
+ .setLaunchedFromPid(callingPid)
+ .setLaunchedFromUid(callingUid)
+ .setLaunchedFromPackage(callingPackage)
+ .setLaunchedFromFeature(callingFeatureId)
+ .setIntent(intent)
+ .setResolvedType(resolvedType)
+ .setActivityInfo(aInfo)
+ .setConfiguration(mService.getGlobalConfiguration())
+ .setResultTo(resultRecord)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setComponentSpecified(request.componentSpecified)
+ .setRootVoiceInteraction(voiceSession != null)
+ .setActivityOptions(checkedOptions)
+ .setSourceRecord(sourceRecord)
+ .build();
- final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
- callingPackage, callingFeatureId, intent, resolvedType, aInfo,
- mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,
- request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,
- sourceRecord);
mLastStartActivityRecord = r;
if (r.appTimeTracker == null && sourceRecord != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index d94c7af0f190..73d99724c65f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2570,6 +2570,11 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT,
task.getRootTask());
+
+ // As it doesn't go to ActivityStarter.executeRequest() path, we need to resume
+ // app switching here also.
+ mService.resumeAppSwitches();
+
return ActivityManager.START_TASK_TO_FRONT;
}
callingPackage = task.mCallingPackage;
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index a4ac16f2ec77..cd3f32278165 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -307,6 +307,11 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
return this;
}
+ /** Cheap way of doing cast and instanceof. */
+ DisplayArea.Tokens asTokens() {
+ return null;
+ }
+
@Override
void forAllDisplayAreas(Consumer<DisplayArea> callback) {
super.forAllDisplayAreas(callback);
@@ -544,6 +549,11 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
mLastOrientationSource = win;
return req;
}
+
+ @Override
+ final DisplayArea.Tokens asTokens() {
+ return this;
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index 211bd5d9eb77..7573e92e82a8 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -86,7 +86,7 @@ public abstract class DisplayAreaPolicy {
@Override
public DisplayAreaPolicy instantiate(WindowManagerService wmService,
DisplayContent content, RootDisplayArea root,
- DisplayArea<? extends WindowContainer> imeContainer) {
+ DisplayArea.Tokens imeContainer) {
final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
"DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
final List<TaskDisplayArea> tdaList = new ArrayList<>();
@@ -151,7 +151,7 @@ public abstract class DisplayAreaPolicy {
* @see DisplayAreaPolicy#DisplayAreaPolicy
*/
DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content,
- RootDisplayArea root, DisplayArea<? extends WindowContainer> imeContainer);
+ RootDisplayArea root, DisplayArea.Tokens imeContainer);
/**
* Instantiates the device-specific {@link Provider}.
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 6a420874b924..bc3220673ed3 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -247,7 +247,7 @@ class DisplayAreaPolicyBuilder {
private final ArrayList<DisplayAreaPolicyBuilder.Feature> mFeatures = new ArrayList<>();
private final ArrayList<TaskDisplayArea> mTaskDisplayAreas = new ArrayList<>();
@Nullable
- private DisplayArea<? extends WindowContainer> mImeContainer;
+ private DisplayArea.Tokens mImeContainer;
HierarchyBuilder(RootDisplayArea root) {
mRoot = root;
@@ -270,7 +270,7 @@ class DisplayAreaPolicyBuilder {
}
/** Sets IME container as a child of this hierarchy root. */
- HierarchyBuilder setImeContainer(DisplayArea<? extends WindowContainer> imeContainer) {
+ HierarchyBuilder setImeContainer(DisplayArea.Tokens imeContainer) {
mImeContainer = imeContainer;
return this;
}
@@ -706,6 +706,10 @@ class DisplayAreaPolicyBuilder {
private DisplayArea createArea(DisplayArea<DisplayArea> parent,
DisplayArea.Tokens[] areaForLayer) {
if (mExisting != null) {
+ if (mExisting.asTokens() != null) {
+ // Store the WindowToken container for layers
+ fillAreaForLayers(mExisting.asTokens(), areaForLayer);
+ }
return mExisting;
}
if (mSkipTokens) {
@@ -722,14 +726,18 @@ class DisplayAreaPolicyBuilder {
if (mFeature == null) {
final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,
"Leaf:" + mMinLayer + ":" + mMaxLayer);
- for (int i = mMinLayer; i <= mMaxLayer; i++) {
- areaForLayer[i] = leaf;
- }
+ fillAreaForLayers(leaf, areaForLayer);
return leaf;
} else {
return mFeature.mNewDisplayAreaSupplier.create(parent.mWmService, type,
mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer, mFeature.mId);
}
}
+
+ private void fillAreaForLayers(DisplayArea.Tokens leaf, DisplayArea.Tokens[] areaForLayer) {
+ for (int i = mMinLayer; i <= mMaxLayer; i++) {
+ areaForLayer[i] = leaf;
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index aa603aba0f78..f4fdd7370e9c 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -16,9 +16,9 @@
package com.android.server.wm;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -64,7 +64,7 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
? "DisplayWindowSettingsProvider" : TAG_WM;
private static final String DATA_DISPLAY_SETTINGS_FILE_PATH = "system/display_settings.xml";
- private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/display_settings.xml";
+ private static final String VENDOR_DISPLAY_SETTINGS_FILE_PATH = "etc/display_settings.xml";
private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
private static final int IDENTIFIER_UNIQUE_ID = 0;
@@ -86,34 +86,8 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
void finishWrite(OutputStream os, boolean success);
}
- private final ReadableSettingsStorage mVendorSettingsStorage;
- /**
- * The preferred type of a display identifier to use when storing and retrieving entries from
- * the base (vendor) settings file.
- *
- * @see #getIdentifier(DisplayInfo, int)
- */
- @DisplayIdentifierType
- private int mVendorIdentifierType;
- private final Map<String, SettingsEntry> mVendorSettings = new HashMap<>();
-
- private final WritableSettingsStorage mOverrideSettingsStorage;
- /**
- * The preferred type of a display identifier to use when storing and retrieving entries from
- * the data (override) settings file.
- *
- * @see #getIdentifier(DisplayInfo, int)
- */
- @DisplayIdentifierType
- private int mOverrideIdentifierType;
- private final Map<String, SettingsEntry> mOverrideSettings = new HashMap<>();
-
- /**
- * Enables or disables settings provided from the vendor settings storage.
- *
- * @see #setVendorSettingsIgnored(boolean)
- */
- private boolean mIgnoreVendorSettings = true;
+ private ReadableSettings mBaseSettings;
+ private final WritableSettings mOverrideSettings;
DisplayWindowSettingsProvider() {
this(new AtomicFileStorage(getVendorSettingsFile()),
@@ -121,43 +95,48 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
}
@VisibleForTesting
- DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage vendorSettingsStorage,
+ DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage baseSettingsStorage,
@NonNull WritableSettingsStorage overrideSettingsStorage) {
- mVendorSettingsStorage = vendorSettingsStorage;
- mOverrideSettingsStorage = overrideSettingsStorage;
- readSettings();
+ mBaseSettings = new ReadableSettings(baseSettingsStorage);
+ mOverrideSettings = new WritableSettings(overrideSettingsStorage);
}
/**
- * Enables or disables settings provided from the vendor settings storage. If {@code true}, the
- * vendor settings will be ignored and only the override settings will be returned from
- * {@link #getSettings(DisplayInfo)}. If {@code false}, settings returned from
- * {@link #getSettings(DisplayInfo)} will be a merged result of the vendor settings and the
- * override settings.
+ * Overrides the path for the file that should be used to read base settings. If {@code null} is
+ * passed the default base settings file path will be used.
+ *
+ * @see #VENDOR_DISPLAY_SETTINGS_FILE_PATH
*/
- void setVendorSettingsIgnored(boolean ignored) {
- mIgnoreVendorSettings = ignored;
+ void setBaseSettingsFilePath(@Nullable String path) {
+ AtomicFile settingsFile;
+ if (path != null) {
+ settingsFile = new AtomicFile(new File(path), WM_DISPLAY_COMMIT_TAG);
+ } else {
+ settingsFile = getVendorSettingsFile();
+ }
+
+ setBaseSettingsStorage(new AtomicFileStorage(settingsFile));
}
/**
- * Returns whether or not the vendor settings are being ignored.
+ * Overrides the storage that should be used to read base settings.
*
- * @see #setVendorSettingsIgnored(boolean)
+ * @see #setBaseSettingsFilePath(String)
*/
@VisibleForTesting
- boolean getVendorSettingsIgnored() {
- return mIgnoreVendorSettings;
+ void setBaseSettingsStorage(@NonNull ReadableSettingsStorage baseSettingsStorage) {
+ mBaseSettings = new ReadableSettings(baseSettingsStorage);
}
@Override
@NonNull
public SettingsEntry getSettings(@NonNull DisplayInfo info) {
- SettingsEntry vendorSettings = getVendorSettingsEntry(info);
- SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
- if (vendorSettings == null) {
+ SettingsEntry baseSettings = mBaseSettings.getSettingsEntry(info);
+ SettingsEntry overrideSettings = mOverrideSettings.getOrCreateSettingsEntry(info);
+ if (baseSettings == null) {
return new SettingsEntry(overrideSettings);
} else {
- SettingsEntry mergedSettings = new SettingsEntry(vendorSettings);
+ SettingsEntry mergedSettings = new SettingsEntry(baseSettings);
mergedSettings.updateFrom(overrideSettings);
return mergedSettings;
}
@@ -166,99 +145,126 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
@Override
@NonNull
public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) {
- return new SettingsEntry(getOrCreateOverrideSettingsEntry(info));
+ return new SettingsEntry(mOverrideSettings.getOrCreateSettingsEntry(info));
}
@Override
public void updateOverrideSettings(@NonNull DisplayInfo info,
@NonNull SettingsEntry overrides) {
- final SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
- boolean changed = overrideSettings.setTo(overrides);
- if (changed) {
- writeOverrideSettings();
- }
+ mOverrideSettings.updateSettingsEntry(info, overrides);
}
- @Nullable
- private SettingsEntry getVendorSettingsEntry(DisplayInfo info) {
- if (mIgnoreVendorSettings) {
+ /**
+ * Class that allows reading {@link SettingsEntry entries} from a
+ * {@link ReadableSettingsStorage}.
+ */
+ private static class ReadableSettings {
+ /**
+ * The preferred type of a display identifier to use when storing and retrieving entries
+ * from the settings entries.
+ *
+ * @see #getIdentifier(DisplayInfo)
+ */
+ @DisplayIdentifierType
+ protected int mIdentifierType;
+ protected final Map<String, SettingsEntry> mSettings = new HashMap<>();
+
+ ReadableSettings(ReadableSettingsStorage settingsStorage) {
+ loadSettings(settingsStorage);
+ }
+
+ @Nullable
+ final SettingsEntry getSettingsEntry(DisplayInfo info) {
+ final String identifier = getIdentifier(info);
+ SettingsEntry settings;
+ // Try to get corresponding settings using preferred identifier for the current config.
+ if ((settings = mSettings.get(identifier)) != null) {
+ return settings;
+ }
+ // Else, fall back to the display name.
+ if ((settings = mSettings.get(info.name)) != null) {
+ // Found an entry stored with old identifier.
+ mSettings.remove(info.name);
+ mSettings.put(identifier, settings);
+ return settings;
+ }
return null;
}
- final String identifier = getIdentifier(info, mVendorIdentifierType);
- SettingsEntry settings;
- // Try to get corresponding settings using preferred identifier for the current config.
- if ((settings = mVendorSettings.get(identifier)) != null) {
- return settings;
+ /** Gets the identifier of choice for the current config. */
+ protected final String getIdentifier(DisplayInfo displayInfo) {
+ if (mIdentifierType == IDENTIFIER_PORT && displayInfo.address != null) {
+ // Config suggests using port as identifier for physical displays.
+ if (displayInfo.address instanceof DisplayAddress.Physical) {
+ return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort();
+ }
+ }
+ return displayInfo.uniqueId;
}
- // Else, fall back to the display name.
- if ((settings = mVendorSettings.get(info.name)) != null) {
- // Found an entry stored with old identifier.
- mVendorSettings.remove(info.name);
- mVendorSettings.put(identifier, settings);
- return settings;
+
+ private void loadSettings(ReadableSettingsStorage settingsStorage) {
+ FileData fileData = readSettings(settingsStorage);
+ if (fileData != null) {
+ mIdentifierType = fileData.mIdentifierType;
+ mSettings.putAll(fileData.mSettings);
+ }
}
- return null;
}
- @NonNull
- private SettingsEntry getOrCreateOverrideSettingsEntry(DisplayInfo info) {
- final String identifier = getIdentifier(info, mOverrideIdentifierType);
- SettingsEntry settings;
- // Try to get corresponding settings using preferred identifier for the current config.
- if ((settings = mOverrideSettings.get(identifier)) != null) {
- return settings;
- }
- // Else, fall back to the display name.
- if ((settings = mOverrideSettings.get(info.name)) != null) {
- // Found an entry stored with old identifier.
- mOverrideSettings.remove(info.name);
- mOverrideSettings.put(identifier, settings);
- writeOverrideSettings();
- return settings;
+ /**
+ * Class that allows reading {@link SettingsEntry entries} from, and writing entries to, a
+ * {@link WritableSettingsStorage}.
+ */
+ private static final class WritableSettings extends ReadableSettings {
+ private final WritableSettingsStorage mSettingsStorage;
+
+ WritableSettings(WritableSettingsStorage settingsStorage) {
+ super(settingsStorage);
+ mSettingsStorage = settingsStorage;
}
- settings = new SettingsEntry();
- mOverrideSettings.put(identifier, settings);
- return settings;
- }
+ @NonNull
+ SettingsEntry getOrCreateSettingsEntry(DisplayInfo info) {
+ final String identifier = getIdentifier(info);
+ SettingsEntry settings;
+ // Try to get corresponding settings using preferred identifier for the current config.
+ if ((settings = mSettings.get(identifier)) != null) {
+ return settings;
+ }
+ // Else, fall back to the display name.
+ if ((settings = mSettings.get(info.name)) != null) {
+ // Found an entry stored with old identifier.
+ mSettings.remove(info.name);
+ mSettings.put(identifier, settings);
+ writeSettings();
+ return settings;
+ }
- private void readSettings() {
- FileData vendorFileData = readSettings(mVendorSettingsStorage);
- if (vendorFileData != null) {
- mVendorIdentifierType = vendorFileData.mIdentifierType;
- mVendorSettings.putAll(vendorFileData.mSettings);
+ settings = new SettingsEntry();
+ mSettings.put(identifier, settings);
+ return settings;
}
- FileData overrideFileData = readSettings(mOverrideSettingsStorage);
- if (overrideFileData != null) {
- mOverrideIdentifierType = overrideFileData.mIdentifierType;
- mOverrideSettings.putAll(overrideFileData.mSettings);
+ void updateSettingsEntry(DisplayInfo info, SettingsEntry settings) {
+ final SettingsEntry overrideSettings = getOrCreateSettingsEntry(info);
+ final boolean changed = overrideSettings.setTo(settings);
+ if (changed) {
+ writeSettings();
+ }
}
- }
-
- private void writeOverrideSettings() {
- FileData fileData = new FileData();
- fileData.mIdentifierType = mOverrideIdentifierType;
- fileData.mSettings.putAll(mOverrideSettings);
- writeSettings(mOverrideSettingsStorage, fileData);
- }
- /** Gets the identifier of choice for the current config. */
- private static String getIdentifier(DisplayInfo displayInfo, @DisplayIdentifierType int type) {
- if (type == IDENTIFIER_PORT && displayInfo.address != null) {
- // Config suggests using port as identifier for physical displays.
- if (displayInfo.address instanceof DisplayAddress.Physical) {
- return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort();
- }
+ private void writeSettings() {
+ FileData fileData = new FileData();
+ fileData.mIdentifierType = mIdentifierType;
+ fileData.mSettings.putAll(mSettings);
+ DisplayWindowSettingsProvider.writeSettings(mSettingsStorage, fileData);
}
- return displayInfo.uniqueId;
}
@NonNull
private static AtomicFile getVendorSettingsFile() {
final File vendorFile = new File(Environment.getVendorDirectory(),
- VENDOR_DISPLAY_SETTINGS_PATH);
+ VENDOR_DISPLAY_SETTINGS_FILE_PATH);
return new AtomicFile(vendorFile, WM_DISPLAY_COMMIT_TAG);
}
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index da04f438a496..c4fcea68a6fc 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -16,11 +16,17 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
import static android.window.DisplayAreaOrganizer.FEATURE_IME_PLACEHOLDER;
import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
+import android.annotation.Nullable;
+
+import com.android.server.policy.WindowManagerPolicy;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -72,7 +78,8 @@ class RootDisplayArea extends DisplayArea<DisplayArea> {
* match the root.
*/
void placeImeContainer(DisplayArea.Tokens imeContainer) {
- if (imeContainer.getRootDisplayArea() == this) {
+ final RootDisplayArea previousRoot = imeContainer.getRootDisplayArea();
+ if (previousRoot == this) {
// No need to reparent if IME container is below the same root.
return;
}
@@ -88,7 +95,9 @@ class RootDisplayArea extends DisplayArea<DisplayArea> {
+ "FEATURE_IME_PLACEHOLDER");
}
+ previousRoot.updateImeContainerForLayers(null /* imeContainer */);
imeContainer.reparent(imeDisplayAreas.get(0), POSITION_TOP);
+ updateImeContainerForLayers(imeContainer);
return;
}
}
@@ -119,4 +128,10 @@ class RootDisplayArea extends DisplayArea<DisplayArea> {
mAreaForLayer = areaForLayer;
mFeatureToDisplayAreas = featureToDisplayAreas;
}
+
+ private void updateImeContainerForLayers(@Nullable DisplayArea.Tokens imeContainer) {
+ final WindowManagerPolicy policy = mWmService.mPolicy;
+ mAreaForLayer[policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)] = imeContainer;
+ mAreaForLayer[policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD_DIALOG)] = imeContainer;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 87a5baf6feb0..7c290c465c32 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -44,8 +44,8 @@ import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDO
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
-import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS;
import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR;
+import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
@@ -796,8 +796,8 @@ public class WindowManagerService extends IWindowManager.Stub
DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM);
private final Uri mRenderShadowsInCompositorUri = Settings.Global.getUriFor(
DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR);
- private final Uri mIgnoreVendorDisplaySettingsUri = Settings.Global.getUriFor(
- DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS);
+ private final Uri mDisplaySettingsPathUri = Settings.Global.getUriFor(
+ DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
public SettingsObserver() {
super(new Handler());
@@ -822,7 +822,7 @@ public class WindowManagerService extends IWindowManager.Stub
UserHandle.USER_ALL);
resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this,
UserHandle.USER_ALL);
- resolver.registerContentObserver(mIgnoreVendorDisplaySettingsUri, false, this,
+ resolver.registerContentObserver(mDisplaySettingsPathUri, false, this,
UserHandle.USER_ALL);
}
@@ -867,8 +867,8 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- if (mIgnoreVendorDisplaySettingsUri.equals(uri)) {
- updateIgnoreVendorDisplaySettings();
+ if (mDisplaySettingsPathUri.equals(uri)) {
+ updateDisplaySettingsLocation();
return;
}
@@ -962,12 +962,12 @@ public class WindowManagerService extends IWindowManager.Stub
mAtmService.mSizeCompatFreeform = sizeCompatFreeform;
}
- void updateIgnoreVendorDisplaySettings() {
+ void updateDisplaySettingsLocation() {
final ContentResolver resolver = mContext.getContentResolver();
- final boolean ignoreVendorSettings = Settings.Global.getInt(resolver,
- DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0;
+ final String filePath = Settings.Global.getString(resolver,
+ DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
synchronized (mGlobalLock) {
- mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorSettings);
+ mDisplayWindowSettingsProvider.setBaseSettingsFilePath(filePath);
mRoot.forAllDisplays(display -> {
mDisplayWindowSettings.applySettingsToDisplayLocked(display);
display.reconfigureDisplayLocked();
@@ -1329,10 +1329,12 @@ public class WindowManagerService extends IWindowManager.Stub
mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver,
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;
- final boolean ignoreVendorDisplaySettings = Settings.Global.getInt(resolver,
- DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0;
+ final String displaySettingsPath = Settings.Global.getString(resolver,
+ DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
mDisplayWindowSettingsProvider = new DisplayWindowSettingsProvider();
- mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorDisplaySettings);
+ if (displaySettingsPath != null) {
+ mDisplayWindowSettingsProvider.setBaseSettingsFilePath(displaySettingsPath);
+ }
mDisplayWindowSettings = new DisplayWindowSettings(this, mDisplayWindowSettingsProvider);
IntentFilter filter = new IntentFilter();
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 6da9517743d2..d37c7b03dfb5 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -152,7 +152,7 @@ cc_defaults {
"android.hardware.power.stats@1.0",
"android.hardware.thermal@1.0",
"android.hardware.tv.input@1.0",
- "android.hardware.vibrator-cpp",
+ "android.hardware.vibrator-unstable-cpp",
"android.hardware.vibrator@1.0",
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9e0fb567975a..13450be73d88 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -238,16 +238,16 @@ public:
/* --- InputReaderPolicyInterface implementation --- */
- virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
- virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId);
- virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices);
- virtual std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
- const InputDeviceIdentifier& identifier);
- virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier);
- virtual TouchAffineTransformation getTouchAffineTransformation(JNIEnv *env,
- jfloatArray matrixArr);
- virtual TouchAffineTransformation getTouchAffineTransformation(
- const std::string& inputDeviceDescriptor, int32_t surfaceRotation);
+ void getReaderConfiguration(InputReaderConfiguration* outConfig) override;
+ std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override;
+ void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override;
+ std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
+ const InputDeviceIdentifier& identifier) override;
+ std::string getDeviceAlias(const InputDeviceIdentifier& identifier) override;
+ TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
+ int32_t surfaceRotation) override;
+
+ TouchAffineTransformation getTouchAffineTransformation(JNIEnv* env, jfloatArray matrixArr);
/* --- InputDispatcherPolicyInterface implementation --- */
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 05b1e4253bc0..ce61d50df1d9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -101,9 +101,4 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public boolean canProfileOwnerResetPasswordWhenLocked(int userId) {
return false;
}
-
- public boolean hasKeyPair(String callerPackage, String alias) {
- // STOPSHIP: implement delegation code in ArcDevicePolicyManagerWrapperService & nuke this.
- return false;
- }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 01b8c0b99c68..513543e0aec8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -218,8 +218,10 @@ import android.os.Process;
import android.os.RecoverySystem;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
+import android.os.ShellCallback;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -267,7 +269,6 @@ import android.view.inputmethod.InputMethodInfo;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.compat.IPlatformCompat;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -555,7 +556,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private final LockSettingsInternal mLockSettingsInternal;
private final DeviceAdminServiceController mDeviceAdminServiceController;
private final OverlayPackagesProvider mOverlayPackagesProvider;
- private final IPlatformCompat mIPlatformCompat;
private final DevicePolicyCacheImpl mPolicyCache = new DevicePolicyCacheImpl();
private final DeviceStateCacheImpl mStateCache = new DeviceStateCacheImpl();
@@ -1163,11 +1163,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return LocalServices.getService(LockSettingsInternal.class);
}
- IPlatformCompat getIPlatformCompat() {
- return IPlatformCompat.Stub.asInterface(
- ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
- }
-
boolean hasUserSetupCompleted(DevicePolicyData userData) {
return userData.mUserSetupComplete;
}
@@ -1438,7 +1433,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mUsageStatsManagerInternal = Objects.requireNonNull(
injector.getUsageStatsManagerInternal());
mIPackageManager = Objects.requireNonNull(injector.getIPackageManager());
- mIPlatformCompat = Objects.requireNonNull(injector.getIPlatformCompat());
mIPermissionManager = Objects.requireNonNull(injector.getIPermissionManager());
mTelephonyManager = Objects.requireNonNull(injector.getTelephonyManager());
@@ -3382,13 +3376,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private boolean passwordQualityInvocationOrderCheckEnabled(String packageName, int userId) {
- try {
- return mIPlatformCompat.isChangeEnabledByPackageName(ADMIN_APP_PASSWORD_COMPLEXITY,
- packageName, userId);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
- }
- return getTargetSdk(packageName, userId) > Build.VERSION_CODES.Q;
+ return mInjector.isChangeEnabled(ADMIN_APP_PASSWORD_COMPLEXITY, packageName, userId);
}
/**
@@ -4302,11 +4290,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
updatePasswordQualityCacheForUserGroup(caller.getUserId());
saveSettingsLocked(caller.getUserId());
});
+
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PASSWORD_COMPLEXITY)
+ .setAdmin(admin.info.getPackageName())
+ .setInt(passwordComplexity)
+ .setBoolean(calledOnParent)
+ .write();
}
logPasswordComplexityRequiredIfSecurityLogEnabled(admin.info.getComponent(),
caller.getUserId(), calledOnParent, passwordComplexity);
}
- //TODO: Log metrics.
}
private void logPasswordComplexityRequiredIfSecurityLogEnabled(ComponentName who, int userId,
@@ -8741,6 +8735,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
pw.decreaseIndent();
}
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+ new DevicePolicyManagerServiceShellCommand(DevicePolicyManagerService.this).exec(
+ this, in, out, err, args, callback, resultReceiver);
+
+ }
+
private String getEncryptionStatusName(int encryptionStatus) {
switch (encryptionStatus) {
case DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE:
@@ -11048,16 +11050,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private boolean isSetSecureSettingLocationModeCheckEnabled(String packageName, int userId) {
- long ident = mInjector.binderClearCallingIdentity();
- try {
- return mIPlatformCompat.isChangeEnabledByPackageName(USE_SET_LOCATION_ENABLED,
- packageName, userId);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
- return getTargetSdk(packageName, userId) > Build.VERSION_CODES.Q;
- } finally {
- mInjector.binderRestoreCallingIdentity(ident);
- }
+ return mInjector.isChangeEnabled(USE_SET_LOCATION_ENABLED, packageName, userId);
}
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
new file mode 100644
index 000000000000..0b0aee9afa6d
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.devicepolicy;
+
+import android.app.admin.DevicePolicyManager;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
+
+ private static final String CMD_IS_SAFE_OPERATION = "is-operation-safe";
+
+ private final DevicePolicyManagerService mService;
+
+ DevicePolicyManagerServiceShellCommand(DevicePolicyManagerService service) {
+ mService = Objects.requireNonNull(service);
+ }
+
+ @Override
+ public void onHelp() {
+ try (PrintWriter pw = getOutPrintWriter();) {
+ pw.printf("DevicePolicyManager Service (device_policy) commands:\n\n");
+ showHelp(pw);
+ }
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ try (PrintWriter pw = getOutPrintWriter();) {
+ switch (cmd) {
+ case CMD_IS_SAFE_OPERATION:
+ return runIsSafeOperation(pw);
+ default:
+ return onInvalidCommand(pw, cmd);
+ }
+ }
+ }
+
+ private int onInvalidCommand(PrintWriter pw, String cmd) {
+ if (super.handleDefaultCommands(cmd) == 0) {
+ return 0;
+ }
+
+ pw.println("Usage: ");
+ showHelp(pw);
+ return -1;
+ }
+
+
+ private void showHelp(PrintWriter pw) {
+ pw.printf(" help\n");
+ pw.printf(" Prints this help text.\n\n");
+ pw.printf(" %s <OPERATION_ID>\n", CMD_IS_SAFE_OPERATION);
+ pw.printf(" Checks if the give operation is safe \n\n");
+ }
+
+ private int runIsSafeOperation(PrintWriter pw) {
+ int operation = Integer.parseInt(getNextArgRequired());
+ boolean safe = mService.canExecute(operation);
+ pw.printf("Operation %s is %s\n", DevicePolicyManager.operationToString(operation),
+ safe ? "SAFE" : "UNSAFE");
+ return 0;
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 10b3265cd081..6525e1126478 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -47,6 +47,7 @@ import android.content.res.Resources.Theme;
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
import android.graphics.GraphicsStatsService;
+import android.graphics.Typeface;
import android.hardware.display.DisplayManagerInternal;
import android.net.ConnectivityManager;
import android.net.ConnectivityModuleConnector;
@@ -120,6 +121,7 @@ import com.android.server.display.color.ColorDisplayService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.emergency.EmergencyAffordanceService;
import com.android.server.gpu.GpuService;
+import com.android.server.graphics.fonts.FontManagerService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.incident.IncidentCompanionService;
import com.android.server.input.InputManagerService;
@@ -673,6 +675,11 @@ public final class SystemServer implements Dumpable {
SystemServerInitThreadPool tp = SystemServerInitThreadPool.start();
mDumper.addDumpable(tp);
+ // Load preinstalled system fonts for system server, so that WindowManagerService, etc
+ // can start using Typeface. Note that fonts are required not only for text rendering,
+ // but also for some text operations (e.g. TextUtils.makeSafeForPresentation()).
+ Typeface.loadPreinstalledSystemFontMap();
+
// Attach JVMTI agent if this is a debuggable build and the system property is set.
if (Build.IS_DEBUGGABLE) {
// Property is of the form "library_path=parameters".
@@ -1604,6 +1611,10 @@ public final class SystemServer implements Dumpable {
}
t.traceEnd();
+ t.traceBegin("StartFontManagerService");
+ mSystemServiceManager.startService(FontManagerService.Lifecycle.class);
+ t.traceEnd();
+
t.traceBegin("StartTextServicesManager");
mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
t.traceEnd();
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 77090a8e0d83..e2c5e97b8896 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4252,10 +4252,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.packageName = admin1.getPackageName();
mContext.applicationInfo = new ApplicationInfo();
- when(mContext.resources.getColor(eq(R.color.notification_action_list), anyObject()))
- .thenReturn(Color.WHITE);
- when(mContext.resources.getColor(eq(R.color.notification_material_background_color),
- anyObject())).thenReturn(Color.WHITE);
+ when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
@@ -4301,10 +4298,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
setupDeviceOwner();
mContext.packageName = admin1.getPackageName();
mContext.applicationInfo = new ApplicationInfo();
- when(mContext.resources.getColor(eq(R.color.notification_action_list), anyObject()))
- .thenReturn(Color.WHITE);
- when(mContext.resources.getColor(eq(R.color.notification_material_background_color),
- anyObject())).thenReturn(Color.WHITE);
+ when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index cb5ca04c1fde..603608b23172 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -40,6 +40,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.database.ContentObserver;
+import android.hardware.display.DisplayManager;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
@@ -402,7 +403,7 @@ public class DisplayModeDirectorTest {
director.injectVotesByDisplay(votesByDisplay);
assertThat(director.getModeSwitchingType())
- .isNotEqualTo(DisplayModeDirector.SWITCHING_TYPE_NONE);
+ .isNotEqualTo(DisplayManager.SWITCHING_TYPE_NONE);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30);
@@ -411,9 +412,9 @@ public class DisplayModeDirectorTest {
assertThat(desiredSpecs.appRequestRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.baseModeId).isEqualTo(30);
- director.setModeSwitchingType(DisplayModeDirector.SWITCHING_TYPE_NONE);
+ director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_NONE);
assertThat(director.getModeSwitchingType())
- .isEqualTo(DisplayModeDirector.SWITCHING_TYPE_NONE);
+ .isEqualTo(DisplayManager.SWITCHING_TYPE_NONE);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30);
@@ -428,9 +429,9 @@ public class DisplayModeDirectorTest {
final int displayId = 0;
DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
- director.setModeSwitchingType(DisplayModeDirector.SWITCHING_TYPE_WITHIN_GROUPS);
+ director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS);
assertThat(director.getModeSwitchingType())
- .isEqualTo(DisplayModeDirector.SWITCHING_TYPE_WITHIN_GROUPS);
+ .isEqualTo(DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
assertThat(desiredSpecs.allowGroupSwitching).isFalse();
}
@@ -440,9 +441,9 @@ public class DisplayModeDirectorTest {
final int displayId = 0;
DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
- director.setModeSwitchingType(DisplayModeDirector.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS);
+ director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS);
assertThat(director.getModeSwitchingType())
- .isEqualTo(DisplayModeDirector.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS);
+ .isEqualTo(DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
assertThat(desiredSpecs.allowGroupSwitching).isTrue();
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index de9a5e4f0fe7..d10e075c5136 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -18,17 +18,13 @@ package com.android.server.hdmi;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
-import android.annotation.NonNull;
import android.content.Context;
import android.hardware.hdmi.HdmiControlManager;
-import android.os.Looper;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings.Global;
@@ -42,21 +38,15 @@ import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
@SmallTest
@Presubmit
@RunWith(JUnit4.class)
public final class HdmiCecConfigTest {
private static final String TAG = "HdmiCecConfigTest";
- private static final int TIMEOUT_CONTENT_CHANGE_SEC = 4;
-
private Context mContext;
@Mock private HdmiCecConfig.StorageAdapter mStorageAdapter;
- @Mock private HdmiCecConfig.SettingChangeListener mSettingChangeListener;
@Before
public void setUp() throws Exception {
@@ -1029,105 +1019,4 @@ public final class HdmiCecConfigTest {
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED));
}
-
- @Test
- public void registerChangeListener_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
- hdmiCecConfig.registerChangeListener(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
- mSettingChangeListener);
- hdmiCecConfig.setIntValue(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
- HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
- verify(mSettingChangeListener).onChange(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
- }
-
- @Test
- public void removeChangeListener_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
- hdmiCecConfig.registerChangeListener(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
- mSettingChangeListener);
- hdmiCecConfig.removeChangeListener(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
- mSettingChangeListener);
- hdmiCecConfig.setIntValue(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
- HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
- verify(mSettingChangeListener, never()).onChange(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
- }
-
- /**
- * Externally modified Global Settings still need to be supported. This test verifies that
- * setting change notification is being forwarded to listeners registered via HdmiCecConfig.
- */
- @Test
- public void globalSettingObserver_BasicSanity() throws Exception {
- CountDownLatch notifyLatch = new CountDownLatch(1);
- // Get current value of the setting in the system.
- String val = Global.getString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED);
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
- hdmiCecConfig.registerGlobalSettingsObserver(Looper.getMainLooper());
- HdmiCecConfig.SettingChangeListener latchUpdateListener =
- new HdmiCecConfig.SettingChangeListener() {
- @Override
- public void onChange(@NonNull @HdmiControlManager.CecSettingName String setting) {
- notifyLatch.countDown();
- assertThat(setting).isEqualTo(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
- }
- };
- hdmiCecConfig.registerChangeListener(
- HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
- latchUpdateListener);
- // Flip the value of the setting.
- Global.putString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED,
- ((val == null || val.equals("1")) ? "0" : "1"));
- if (!notifyLatch.await(TIMEOUT_CONTENT_CHANGE_SEC, TimeUnit.SECONDS)) {
- fail("Timed out waiting for the notify callback");
- }
- hdmiCecConfig.unregisterGlobalSettingsObserver();
- // Restore the previous value of the setting in the system.
- Global.putString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED, val);
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java
index 72d6caf1a5be..133f630b7a74 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.metrics.LogMaker;
+import android.util.IndentingPrintWriter;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -73,7 +74,7 @@ public class BatterySavingStatsTest {
void assertDumpable() {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
- dump(new PrintWriter(out), ""); // Just make sure it won't crash.
+ dump(new IndentingPrintWriter(new PrintWriter(out))); // Just make sure it won't crash.
}
void advanceClock(int minutes) {
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index c23fb8028224..21396fd0516e 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -525,6 +525,7 @@ public class TimeDetectorStrategyImplTest {
@Test
public void testSuggestNetworkTime_autoTimeEnabled() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoOriginPriorities(ORIGIN_NETWORK)
.pokeAutoTimeDetectionEnabled(true);
NetworkTimeSuggestion timeSuggestion =
@@ -541,6 +542,7 @@ public class TimeDetectorStrategyImplTest {
@Test
public void testSuggestNetworkTime_autoTimeDisabled() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoOriginPriorities(ORIGIN_NETWORK)
.pokeAutoTimeDetectionEnabled(false);
NetworkTimeSuggestion timeSuggestion =
@@ -552,10 +554,26 @@ public class TimeDetectorStrategyImplTest {
}
@Test
- public void testSuggestNetworkTime_telephonySuggestionsBeatNetworkSuggestions() {
+ public void networkTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoOriginPriorities(ORIGIN_NETWORK)
.pokeAutoTimeDetectionEnabled(true);
+ Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+ NetworkTimeSuggestion timeSuggestion = mScript
+ .generateNetworkTimeSuggestion(suggestedTime);
+
+ mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestNetworkSuggestion(null);
+ }
+
+ @Test
+ public void highPrioritySuggestionsShouldBeatLowerPrioritySuggestions() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
+
// Three obviously different times that could not be mistaken for each other.
Instant networkTime1 = ARBITRARY_TEST_TIME;
Instant networkTime2 = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
@@ -576,7 +594,7 @@ public class TimeDetectorStrategyImplTest {
mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, null)
.assertLatestNetworkSuggestion(networkTimeSuggestion1);
assertEquals(networkTimeSuggestion1, mScript.peekLatestValidNetworkSuggestion());
- assertNull(mScript.peekBestTelephonySuggestion());
+ assertNull("No telephony suggestions were made:", mScript.peekBestTelephonySuggestion());
// Simulate a little time passing.
mScript.simulateTimePassing(smallTimeIncrementMillis)
@@ -631,7 +649,9 @@ public class TimeDetectorStrategyImplTest {
mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion2);
assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
- assertNull(mScript.peekBestTelephonySuggestion());
+ assertNull(
+ "Telephony suggestion should be expired:",
+ mScript.peekBestTelephonySuggestion());
// Toggle auto-time off and on to force the detection logic to run.
mScript.simulateAutoTimeDetectionToggle()
@@ -646,27 +666,16 @@ public class TimeDetectorStrategyImplTest {
mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion2);
assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
- assertNull(mScript.peekBestTelephonySuggestion());
- }
-
- @Test
- public void networkTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
-
- Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
- NetworkTimeSuggestion timeSuggestion = mScript
- .generateNetworkTimeSuggestion(suggestedTime);
-
- mScript.simulateNetworkTimeSuggestion(timeSuggestion)
- .verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestNetworkSuggestion(null);
+ assertNull(
+ "Telephony suggestion should still be expired:",
+ mScript.peekBestTelephonySuggestion());
}
@Test
public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_lowerPriorityComesFirst() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
Instant networkTime = ARBITRARY_TEST_TIME;
Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
@@ -686,7 +695,8 @@ public class TimeDetectorStrategyImplTest {
@Test
public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_higherPriorityComesFirst() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
Instant networkTime = ARBITRARY_TEST_TIME;
Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
@@ -706,7 +716,8 @@ public class TimeDetectorStrategyImplTest {
@Test
public void whenHighestPrioritySuggestionIsNotAvailable_fallbacksToNext() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
NetworkTimeSuggestion timeSuggestion =
mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -720,7 +731,7 @@ public class TimeDetectorStrategyImplTest {
public void suggestionsFromSourceNotListedInPrioritiesList_areIgnored() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(new int[]{ORIGIN_TELEPHONY});
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY);
NetworkTimeSuggestion timeSuggestion = mScript.generateNetworkTimeSuggestion(
ARBITRARY_TEST_TIME);
@@ -730,6 +741,19 @@ public class TimeDetectorStrategyImplTest {
.verifySystemClockWasNotSetAndResetCallTracking();
}
+ @Test
+ public void autoOriginPrioritiesList_doesNotAffectManualSuggestion() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(false)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY);
+
+ ManualTimeSuggestion timeSuggestion =
+ mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
+
+ mScript.simulateManualTimeSuggestion(timeSuggestion, true /* expectedResult */)
+ .verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
+ }
+
/**
* A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
* like the real thing should, it also asserts preconditions.
@@ -761,7 +785,7 @@ public class TimeDetectorStrategyImplTest {
}
@Override
- public int[] getAutoOriginPriorities() {
+ public int[] autoOriginPriorities() {
return mAutoOriginPriorities;
}
@@ -886,8 +910,8 @@ public class TimeDetectorStrategyImplTest {
return this;
}
- Script pokeAutoOriginPriorities(@Origin int[] autoOriginPriorites) {
- mFakeCallback.pokeAutoOriginPriorities(autoOriginPriorites);
+ Script pokeAutoOriginPriorities(@Origin int... autoOriginPriorities) {
+ mFakeCallback.pokeAutoOriginPriorities(autoOriginPriorities);
return this;
}
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatchableTester.java b/services/tests/servicestests/src/com/android/server/utils/WatchableTester.java
new file mode 100644
index 000000000000..590df3c18f5a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/utils/WatchableTester.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * A class to count the number of notifications received.
+ */
+public class WatchableTester extends Watcher {
+
+ // The count of changes.
+ public int mChanges = 0;
+
+ // The change count at the last verifyChangeReported() call.
+ public int mLastChangeCount = 0;
+
+ // The single Watchable that this monitors.
+ public final Watchable mWatched;
+
+ // The key, used for messages
+ public String mKey;
+
+ // Clear the changes count, for when the tester is reused.
+ public void clear() {
+ mChanges = 0;
+ }
+
+ /**
+ * Create the WatchableTester with a Watcher and a key. The key is used for logging
+ * test failures.
+ * @param w The {@link Watchable} under test
+ * @param k A key that is prefixed to any test failures.
+ **/
+ public WatchableTester(Watchable w, String k) {
+ mWatched = w;
+ mKey = k;
+ }
+
+ // Listen for events
+ public void register() {
+ mWatched.registerObserver(this);
+ }
+
+ // Stop listening for events
+ public void unregister() {
+ mWatched.unregisterObserver(this);
+ }
+
+ // Count the number of notifications received.
+ @Override
+ public void onChange(Watchable what) {
+ mChanges++;
+ }
+
+ // Verify the count.
+ public void verify(int want, String msg) {
+ assertEquals(mKey + " " + msg, want, mChanges);
+ }
+
+ // Verify that at least one change was reported since the last verify. The actual
+ // number of changes is not important. This resets the count of changes.
+ public void verifyChangeReported(String msg) {
+ assertTrue(mKey + " " + msg, mLastChangeCount < mChanges);
+ mLastChangeCount = mChanges;
+ }
+
+ // Verify that no change was reported since the last verify.
+ public void verifyNoChangeReported(String msg) {
+ assertTrue(mKey + " " + msg, mLastChangeCount == mChanges);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
index 40575e4cf16f..9bea9d4cedbd 100644
--- a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
@@ -18,15 +18,10 @@ package com.android.server.utils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.platform.test.annotations.Presubmit;
+import static org.junit.Assert.fail;
import androidx.test.filters.SmallTest;
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.TraceBuffer;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -42,56 +37,76 @@ import org.junit.Test;
@SmallTest
public class WatcherTest {
+ // A counter to generate unique IDs for Leaf elements.
+ private int mLeafId = 0;
+
+ // Useful indices used int the tests.
+ private static final int INDEX_A = 1;
+ private static final int INDEX_B = 2;
+ private static final int INDEX_C = 3;
+ private static final int INDEX_D = 4;
+
// A small Watchable leaf node
- private class Leaf extends WatchableImpl {
- private int datum = 0;
+ private class Leaf extends WatchableImpl implements Snappable {
+ private int mId;
+ private int mDatum;
+
+ Leaf() {
+ mDatum = 0;
+ mId = mLeafId++;
+ }
+
void set(int i) {
- if (datum != i) {
- datum = i;
+ if (mDatum != i) {
+ mDatum = i;
dispatchChange(this);
}
}
+ int get() {
+ return mDatum;
+ }
void tick() {
- set(datum + 1);
+ set(mDatum + 1);
}
- }
-
- // A top-most watcher. It counts the number of notifications that it receives.
- private class Tester extends Watcher {
- // The count of changes.
- public int changes = 0;
-
- // The single Watchable that this monitors.
- public final Watchable mWatched;
-
- // The key, used for messages
- public String mKey;
-
- // Create the Tester with a Watcher
- public Tester(Watchable w, String k) {
- mWatched = w;
- mKey = k;
+ public Leaf snapshot() {
+ Leaf result = new Leaf();
+ result.mDatum = mDatum;
+ result.mId = mId;
+ result.seal();
+ return result;
}
-
- // Listen for events
- public void register() {
- mWatched.registerObserver(this);
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Leaf) {
+ return mDatum == ((Leaf) o).mDatum && mId == ((Leaf) o).mId;
+ } else {
+ return false;
+ }
}
-
- // Stop listening for events
- public void unregister() {
- mWatched.unregisterObserver(this);
+ @Override
+ public String toString() {
+ return "Leaf(" + mDatum + "," + mId + ")";
}
+ }
- // Count the number of notifications received.
- @Override
- public void onChange(Watchable what) {
- changes++;
+ // Execute the {@link Runnable} and if {@link UnsupportedOperationException} is
+ // thrown, do nothing. If no exception is thrown, fail the test.
+ private void verifySealed(String msg, Runnable test) {
+ try {
+ test.run();
+ fail(msg + " should be sealed");
+ } catch (IllegalStateException e) {
+ // The exception was expected.
}
+ }
- // Verify the count.
- public void verify(int want, String msg) {
- assertEquals(mKey + " " + msg, want, changes);
+ // Execute the {@link Runnable} and if {@link UnsupportedOperationException} is
+ // thrown, fail the test. If no exception is thrown, do nothing.
+ private void verifyNotSealed(String msg, Runnable test) {
+ try {
+ test.run();
+ } catch (IllegalStateException e) {
+ fail(msg + " should be not sealed");
}
}
@@ -104,168 +119,212 @@ public class WatcherTest {
}
@Test
- public void test_notify() {
-
- Tester tester;
+ public void testBasicBehavior() {
+ WatchableTester tester;
// Create a few leaves
- Leaf a = new Leaf();
- Leaf b = new Leaf();
- Leaf c = new Leaf();
- Leaf d = new Leaf();
+ Leaf leafA = new Leaf();
// Basic test. Create a leaf and verify that changes to the leaf get notified to
// the tester.
- tester = new Tester(a, "Leaf");
+ tester = new WatchableTester(leafA, "Leaf");
tester.verify(0, "Initial leaf - no registration");
- a.tick();
+ leafA.tick();
tester.verify(0, "Updates with no registration");
tester.register();
- a.tick();
+ leafA.tick();
tester.verify(1, "Updates with registration");
- a.tick();
- a.tick();
+ leafA.tick();
+ leafA.tick();
tester.verify(3, "Updates with registration");
+ // Create a snapshot. Verify that the snapshot matches the
+ Leaf leafASnapshot = leafA.snapshot();
+ assertEquals("Leaf snapshot", leafA.get(), leafASnapshot.get());
+ leafA.tick();
+ assertTrue(leafA.get() != leafASnapshot.get());
+ tester.verify(4, "Tick after snapshot");
+ verifySealed("Leaf", ()->leafASnapshot.tick());
// Add the same leaf to more than one tester. Verify that a change to the leaf is seen by
// all registered listeners.
- Tester buddy1 = new Tester(a, "Leaf2");
- Tester buddy2 = new Tester(a, "Leaf3");
+ tester.clear();
+ WatchableTester buddy1 = new WatchableTester(leafA, "Leaf2");
+ WatchableTester buddy2 = new WatchableTester(leafA, "Leaf3");
buddy1.verify(0, "Initial leaf - no registration");
buddy2.verify(0, "Initial leaf - no registration");
- a.tick();
- tester.verify(4, "Updates with buddies");
+ leafA.tick();
+ tester.verify(1, "Updates with buddies");
buddy1.verify(0, "Updates - no registration");
buddy2.verify(0, "Updates - no registration");
buddy1.register();
buddy2.register();
buddy1.verify(0, "No updates - registered");
buddy2.verify(0, "No updates - registered");
- a.tick();
+ leafA.tick();
buddy1.verify(1, "First update");
buddy2.verify(1, "First update");
buddy1.unregister();
- a.tick();
+ leafA.tick();
buddy1.verify(1, "Second update - unregistered");
buddy2.verify(2, "Second update");
+ }
- buddy1 = null;
- buddy2 = null;
+ @Test
+ public void testWatchedArrayMap() {
+ WatchableTester tester;
- final int INDEX_A = 1;
- final int INDEX_B = 2;
- final int INDEX_C = 3;
- final int INDEX_D = 4;
+ // Create a few leaves
+ Leaf leafA = new Leaf();
+ Leaf leafB = new Leaf();
+ Leaf leafC = new Leaf();
+ Leaf leafD = new Leaf();
// Test WatchedArrayMap
- WatchedArrayMap<Integer, Leaf> am = new WatchedArrayMap<>();
- am.put(INDEX_A, a);
- am.put(INDEX_B, b);
- tester = new Tester(am, "WatchedArrayMap");
+ WatchedArrayMap<Integer, Leaf> array = new WatchedArrayMap<>();
+ array.put(INDEX_A, leafA);
+ array.put(INDEX_B, leafB);
+ tester = new WatchableTester(array, "WatchedArrayMap");
tester.verify(0, "Initial array - no registration");
- a.tick();
+ leafA.tick();
tester.verify(0, "Updates with no registration");
tester.register();
tester.verify(0, "Updates with no registration");
- a.tick();
+ leafA.tick();
tester.verify(1, "Updates with registration");
- b.tick();
+ leafB.tick();
tester.verify(2, "Updates with registration");
- am.remove(INDEX_B);
+ array.remove(INDEX_B);
tester.verify(3, "Removed b");
- b.tick();
+ leafB.tick();
tester.verify(3, "Updates with b not watched");
- am.put(INDEX_B, b);
- am.put(INDEX_C, b);
+ array.put(INDEX_B, leafB);
+ array.put(INDEX_C, leafB);
tester.verify(5, "Added b twice");
- b.tick();
+ leafB.tick();
tester.verify(6, "Changed b - single notification");
- am.remove(INDEX_C);
+ array.remove(INDEX_C);
tester.verify(7, "Removed first b");
- b.tick();
+ leafB.tick();
tester.verify(8, "Changed b - single notification");
- am.remove(INDEX_B);
+ array.remove(INDEX_B);
tester.verify(9, "Removed second b");
- b.tick();
+ leafB.tick();
tester.verify(9, "Updated b - no change");
- am.clear();
+ array.clear();
tester.verify(10, "Cleared array");
- b.tick();
+ leafB.tick();
tester.verify(10, "Change to b not in array");
// Special methods
- am.put(INDEX_C, c);
+ array.put(INDEX_C, leafC);
tester.verify(11, "Added c");
- c.tick();
+ leafC.tick();
tester.verify(12, "Ticked c");
- am.setValueAt(am.indexOfKey(INDEX_C), d);
+ array.setValueAt(array.indexOfKey(INDEX_C), leafD);
tester.verify(13, "Replaced c with d");
- c.tick();
- d.tick();
+ leafC.tick();
+ leafD.tick();
tester.verify(14, "Ticked d and c (c not registered)");
- am = null;
+ // Snapshot
+ {
+ final WatchedArrayMap<Integer, Leaf> arraySnap = array.snapshot();
+ tester.verify(14, "Generate snapshot (no changes)");
+ // Verify that the snapshot is a proper copy of the source.
+ assertEquals("WatchedArrayMap snap same size",
+ array.size(), arraySnap.size());
+ for (int i = 0; i < array.size(); i++) {
+ for (int j = 0; j < arraySnap.size(); j++) {
+ assertTrue("WatchedArrayMap elements differ",
+ array.valueAt(i) != arraySnap.valueAt(j));
+ }
+ assertTrue("WatchedArrayMap element copy",
+ array.valueAt(i).equals(arraySnap.valueAt(i)));
+ }
+ leafD.tick();
+ tester.verify(15, "Tick after snapshot");
+ // Verify that the snapshot is sealed
+ verifySealed("WatchedArrayMap", ()->arraySnap.put(INDEX_A, leafA));
+ }
+ // Recreate the snapshot since the test corrupted it.
+ {
+ final WatchedArrayMap<Integer, Leaf> arraySnap = array.snapshot();
+ // Verify that elements are also snapshots
+ final Leaf arraySnapElement = arraySnap.valueAt(0);
+ verifySealed("ArraySnapshotElement", ()->arraySnapElement.tick());
+ }
+ }
+
+ @Test
+ public void testWatchedSparseArray() {
+ WatchableTester tester;
+
+ // Create a few leaves
+ Leaf leafA = new Leaf();
+ Leaf leafB = new Leaf();
+ Leaf leafC = new Leaf();
+ Leaf leafD = new Leaf();
// Test WatchedSparseArray
- WatchedSparseArray<Leaf> sa = new WatchedSparseArray<>();
- sa.put(INDEX_A, a);
- sa.put(INDEX_B, b);
- tester = new Tester(sa, "WatchedSparseArray");
+ WatchedSparseArray<Leaf> array = new WatchedSparseArray<>();
+ array.put(INDEX_A, leafA);
+ array.put(INDEX_B, leafB);
+ tester = new WatchableTester(array, "WatchedSparseArray");
tester.verify(0, "Initial array - no registration");
- a.tick();
+ leafA.tick();
tester.verify(0, "Updates with no registration");
tester.register();
tester.verify(0, "Updates with no registration");
- a.tick();
+ leafA.tick();
tester.verify(1, "Updates with registration");
- b.tick();
+ leafB.tick();
tester.verify(2, "Updates with registration");
- sa.remove(INDEX_B);
+ array.remove(INDEX_B);
tester.verify(3, "Removed b");
- b.tick();
+ leafB.tick();
tester.verify(3, "Updates with b not watched");
- sa.put(INDEX_B, b);
- sa.put(INDEX_C, b);
+ array.put(INDEX_B, leafB);
+ array.put(INDEX_C, leafB);
tester.verify(5, "Added b twice");
- b.tick();
+ leafB.tick();
tester.verify(6, "Changed b - single notification");
- sa.remove(INDEX_C);
+ array.remove(INDEX_C);
tester.verify(7, "Removed first b");
- b.tick();
+ leafB.tick();
tester.verify(8, "Changed b - single notification");
- sa.remove(INDEX_B);
+ array.remove(INDEX_B);
tester.verify(9, "Removed second b");
- b.tick();
- tester.verify(9, "Updated b - no change");
- sa.clear();
+ leafB.tick();
+ tester.verify(9, "Updated leafB - no change");
+ array.clear();
tester.verify(10, "Cleared array");
- b.tick();
+ leafB.tick();
tester.verify(10, "Change to b not in array");
// Special methods
- sa.put(INDEX_A, a);
- sa.put(INDEX_B, b);
- sa.put(INDEX_C, c);
+ array.put(INDEX_A, leafA);
+ array.put(INDEX_B, leafB);
+ array.put(INDEX_C, leafC);
tester.verify(13, "Added c");
- c.tick();
+ leafC.tick();
tester.verify(14, "Ticked c");
- sa.setValueAt(sa.indexOfKey(INDEX_C), d);
+ array.setValueAt(array.indexOfKey(INDEX_C), leafD);
tester.verify(15, "Replaced c with d");
- c.tick();
- d.tick();
+ leafC.tick();
+ leafD.tick();
tester.verify(16, "Ticked d and c (c not registered)");
- sa.append(INDEX_D, c);
+ array.append(INDEX_D, leafC);
tester.verify(17, "Append c");
- c.tick();
- d.tick();
+ leafC.tick();
+ leafD.tick();
tester.verify(19, "Ticked d and c");
- assertEquals("Verify four elements", 4, sa.size());
+ assertEquals("Verify four elements", 4, array.size());
// Figure out which elements are at which indices.
Leaf[] x = new Leaf[4];
for (int i = 0; i < 4; i++) {
- x[i] = sa.valueAt(i);
+ x[i] = array.valueAt(i);
}
- sa.removeAtRange(0, 2);
+ array.removeAtRange(0, 2);
tester.verify(20, "Removed two elements in one operation");
x[0].tick();
x[1].tick();
@@ -274,31 +333,77 @@ public class WatcherTest {
x[3].tick();
tester.verify(22, "Ticked two remaining elements");
- sa = null;
+ // Snapshot
+ {
+ final WatchedSparseArray<Leaf> arraySnap = array.snapshot();
+ tester.verify(22, "Generate snapshot (no changes)");
+ // Verify that the snapshot is a proper copy of the source.
+ assertEquals("WatchedSparseArray snap same size",
+ array.size(), arraySnap.size());
+ for (int i = 0; i < array.size(); i++) {
+ for (int j = 0; j < arraySnap.size(); j++) {
+ assertTrue("WatchedSparseArray elements differ",
+ array.valueAt(i) != arraySnap.valueAt(j));
+ }
+ assertTrue("WatchedArrayMap element copy",
+ array.valueAt(i).equals(arraySnap.valueAt(i)));
+ }
+ leafD.tick();
+ tester.verify(23, "Tick after snapshot");
+ // Verify that the array snapshot is sealed
+ verifySealed("WatchedSparseArray", ()->arraySnap.put(INDEX_A, leafB));
+ }
+ // Recreate the snapshot since the test corrupted it.
+ {
+ final WatchedSparseArray<Leaf> arraySnap = array.snapshot();
+ // Verify that elements are also snapshots
+ final Leaf arraySnapElement = arraySnap.valueAt(0);
+ verifySealed("ArraySnapshotElement", ()->arraySnapElement.tick());
+ }
+ }
+
+ @Test
+ public void testWatchedSparseBooleanArray() {
+ WatchableTester tester;
// Test WatchedSparseBooleanArray
- WatchedSparseBooleanArray sb = new WatchedSparseBooleanArray();
- tester = new Tester(sb, "WatchedSparseBooleanArray");
+ WatchedSparseBooleanArray array = new WatchedSparseBooleanArray();
+ tester = new WatchableTester(array, "WatchedSparseBooleanArray");
tester.verify(0, "Initial array - no registration");
- sb.put(INDEX_A, true);
+ array.put(INDEX_A, true);
tester.verify(0, "Updates with no registration");
tester.register();
tester.verify(0, "Updates with no registration");
- sb.put(INDEX_B, true);
+ array.put(INDEX_B, true);
tester.verify(1, "Updates with registration");
- sb.put(INDEX_B, true);
+ array.put(INDEX_B, true);
tester.verify(1, "Null update");
- sb.put(INDEX_B, false);
- sb.put(INDEX_C, true);
+ array.put(INDEX_B, false);
+ array.put(INDEX_C, true);
tester.verify(3, "Updates with registration");
// Special methods
- sb.put(INDEX_C, true);
+ array.put(INDEX_C, true);
tester.verify(3, "Added true, no change");
- sb.setValueAt(sb.indexOfKey(INDEX_C), false);
+ array.setValueAt(array.indexOfKey(INDEX_C), false);
tester.verify(4, "Replaced true with false");
- sb.append(INDEX_D, true);
+ array.append(INDEX_D, true);
tester.verify(5, "Append true");
- sb = null;
+ // Snapshot
+ {
+ WatchedSparseBooleanArray arraySnap = array.snapshot();
+ tester.verify(5, "Generate snapshot");
+ // Verify that the snapshot is a proper copy of the source.
+ assertEquals("WatchedSparseBooleanArray snap same size",
+ array.size(), arraySnap.size());
+ for (int i = 0; i < array.size(); i++) {
+ assertEquals("WatchedSparseArray element copy",
+ array.valueAt(i), arraySnap.valueAt(i));
+ }
+ array.put(INDEX_D, false);
+ tester.verify(6, "Tick after snapshot");
+ // Verify that the array is sealed
+ verifySealed("WatchedSparseBooleanArray", ()->arraySnap.put(INDEX_D, false));
+ }
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 8c2038b59a0f..b3116d970725 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -37,7 +37,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.IntArray;
import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.server.UiServiceTestCase;
@@ -47,7 +46,6 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.xmlpull.v1.XmlPullParser;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
@@ -144,24 +142,24 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
ComponentName component1 = ComponentName.unflattenFromString("package/Component1");
ComponentName component2 = ComponentName.unflattenFromString("package/Component2");
mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
- true);
+ true, true);
verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal(
- any(ComponentName.class), eq(mZero.id), anyBoolean());
+ any(ComponentName.class), eq(mZero.id), anyBoolean(), anyBoolean());
mAssistants.setPackageOrComponentEnabled(component2.flattenToString(), mZero.id, true,
- true);
+ true, true);
verify(mNm, times(1)).setNotificationAssistantAccessGrantedForUserInternal(
- component1, mZero.id, false);
+ component1, mZero.id, false, true);
}
@Test
public void testSetPackageOrComponentEnabled_samePackage() throws Exception {
ComponentName component1 = ComponentName.unflattenFromString("package/Component1");
mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
- true);
+ true, true);
mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
- true);
+ true, true);
verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal(
- any(ComponentName.class), eq(mZero.id), anyBoolean());
+ any(ComponentName.class), eq(mZero.id), anyBoolean(), anyBoolean());
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 60832374ac28..5cf529a239dc 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -172,7 +172,6 @@ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.InstanceIdSequenceFake;
import com.android.internal.statusbar.NotificationVisibility;
-import com.android.internal.util.FastXmlSerializer;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -196,8 +195,6 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -357,12 +354,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Override
protected void setNotificationAssistantAccessGrantedForUserInternal(
- ComponentName assistant, int userId, boolean granted) {
+ ComponentName assistant, int userId, boolean granted, boolean userSet) {
if (mNotificationAssistantAccessGrantedCallback != null) {
- mNotificationAssistantAccessGrantedCallback.onGranted(assistant, userId, granted);
+ mNotificationAssistantAccessGrantedCallback.onGranted(assistant, userId, granted,
+ userSet);
return;
}
- super.setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
+ super.setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted,
+ userSet);
}
@Override
@@ -376,7 +375,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
interface NotificationAssistantAccessGrantedCallback {
- void onGranted(ComponentName assistant, int userId, boolean granted);
+ void onGranted(ComponentName assistant, int userId, boolean granted, boolean userSet);
}
}
@@ -899,7 +898,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setDefaultAssistantForUser(userId);
verify(mAssistants).setPackageOrComponentEnabled(
- eq(testComponent), eq(userId), eq(true), eq(true));
+ eq(testComponent), eq(userId), eq(true), eq(true), eq(false));
}
@Test
@@ -2909,7 +2908,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), user.getIdentifier(), true, true);
+ c.flattenToString(), user.getIdentifier(), true, true, true);
verify(mAssistants).setUserSet(10, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, true);
@@ -2953,7 +2952,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.getPackageName(), user.getIdentifier(), true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
- any(), anyInt(), anyBoolean(), anyBoolean());
+ any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
verify(mListeners, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -2968,7 +2967,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
- any(), anyInt(), anyBoolean(), anyBoolean());
+ any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
}
@Test
@@ -2983,7 +2982,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), 0, true, true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -3005,9 +3004,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), 0, true, true, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 10, true, true);
+ c.flattenToString(), 10, true, true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
@@ -3031,7 +3030,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationAssistantAccessGranted(null, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, false);
+ c.flattenToString(), 0, true, false, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, false);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -3055,7 +3054,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
null, user.getIdentifier(), true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), user.getIdentifier(), true, false);
+ c.flattenToString(), user.getIdentifier(), true, false, true);
verify(mAssistants).setUserSet(10, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, false);
@@ -3084,9 +3083,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
null, user.getIdentifier(), true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), user.getIdentifier(), true, false);
+ c.flattenToString(), user.getIdentifier(), true, false, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), ui10.id, true, false);
+ c.flattenToString(), ui10.id, true, false, true);
verify(mAssistants).setUserSet(0, true);
verify(mAssistants).setUserSet(10, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
@@ -3106,7 +3105,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.getPackageName(), 0, true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
- any(), anyInt(), anyBoolean(), anyBoolean());
+ any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
verify(mListeners, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3191,7 +3190,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), 0, true, true, true);
}
@Test
@@ -3207,7 +3206,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.getPackageName(), 0, true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
- any(), anyInt(), anyBoolean(), anyBoolean());
+ any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
}
@Test
@@ -5419,7 +5418,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setDefaultAssistantForUser(0);
verify(mNotificationAssistantAccessGrantedCallback)
- .onGranted(eq(xmlConfig), eq(0), eq(true));
+ .onGranted(eq(xmlConfig), eq(0), eq(true), eq(false));
}
@Test
@@ -5441,7 +5440,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setDefaultAssistantForUser(0);
verify(mNotificationAssistantAccessGrantedCallback)
- .onGranted(eq(deviceConfig), eq(0), eq(true));
+ .onGranted(eq(deviceConfig), eq(0), eq(true), eq(false));
}
@Test
@@ -5464,7 +5463,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setDefaultAssistantForUser(0);
verify(mNotificationAssistantAccessGrantedCallback)
- .onGranted(eq(xmlConfig), eq(0), eq(true));
+ .onGranted(eq(xmlConfig), eq(0), eq(true), eq(false));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 28c31843de57..2f34f708a562 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -384,6 +384,7 @@ public class ActivityRecordTests extends WindowTestsBase {
.build();
final Task task = activity.getTask();
activity.setState(DESTROYED, "Testing");
+ clearInvocations(mAtm.getLifecycleManager());
final Configuration newConfig = new Configuration(task.getConfiguration());
newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
@@ -408,6 +409,7 @@ public class ActivityRecordTests extends WindowTestsBase {
activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
activity.getConfiguration()));
+ clearInvocations(mAtm.getLifecycleManager());
final Configuration newConfig = new Configuration(activity.getConfiguration());
final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
@@ -596,6 +598,7 @@ public class ActivityRecordTests extends WindowTestsBase {
final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
try {
+ clearInvocations(mAtm.getLifecycleManager());
doReturn(false).when(stack).isTranslucent(any());
assertTrue(task.shouldBeVisible(null /* starting */));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index 8e6b6fab19eb..266ce5ba0e68 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -20,6 +20,7 @@ import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
@@ -82,7 +83,7 @@ public class DisplayAreaPolicyBuilderTest {
private TestWindowManagerPolicy mPolicy = new TestWindowManagerPolicy(null, null);
private WindowManagerService mWms;
private RootDisplayArea mRoot;
- private DisplayArea<WindowContainer> mImeContainer;
+ private DisplayArea.Tokens mImeContainer;
private DisplayContent mDisplayContent;
private TaskDisplayArea mDefaultTaskDisplayArea;
private List<TaskDisplayArea> mTaskDisplayAreaList;
@@ -95,7 +96,7 @@ public class DisplayAreaPolicyBuilderTest {
public void setup() {
mWms = mSystemServices.getWindowManagerService();
mRoot = new SurfacelessDisplayAreaRoot(mWms);
- mImeContainer = new DisplayArea<>(mWms, ABOVE_TASKS, "Ime");
+ mImeContainer = new DisplayArea.Tokens(mWms, ABOVE_TASKS, "ImeContainer");
mDisplayContent = mock(DisplayContent.class);
mDefaultTaskDisplayArea = new TaskDisplayArea(mDisplayContent, mWms, "Tasks",
FEATURE_DEFAULT_TASK_CONTAINER);
@@ -148,6 +149,10 @@ public class DisplayAreaPolicyBuilderTest {
// The IME is below both foo and bar.
assertThat(fooDescendantMatcher.matches(mImeContainer)).isTrue();
assertThat(barDescendantMatcher.matches(mImeContainer)).isTrue();
+ assertThat(policy.findAreaForToken(tokenOfType(TYPE_INPUT_METHOD)))
+ .isEqualTo(mImeContainer);
+ assertThat(policy.findAreaForToken(tokenOfType(TYPE_INPUT_METHOD_DIALOG)))
+ .isEqualTo(mImeContainer);
List<DisplayArea<?>> actualOrder = collectLeafAreas(mRoot);
Map<DisplayArea<?>, Set<Integer>> zSets = calculateZSets(policy, mImeContainer,
@@ -547,7 +552,7 @@ public class DisplayAreaPolicyBuilderTest {
private Map<DisplayArea<?>, Set<Integer>> calculateZSets(
DisplayAreaPolicyBuilder.Result policy,
- DisplayArea<WindowContainer> ime,
+ DisplayArea.Tokens ime,
DisplayArea<Task> tasks) {
Map<DisplayArea<?>, Set<Integer>> zSets = new HashMap<>();
int[] types = {TYPE_STATUS_BAR, TYPE_NAVIGATION_BAR, TYPE_PRESENTATION,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
index 5a47493c12cd..496b2b744712 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
@@ -69,7 +69,7 @@ public class DisplayAreaPolicyTests {
WindowManagerService wms = mSystemServices.getWindowManagerService();
mRoot = new SurfacelessDisplayAreaRoot(wms);
spyOn(mRoot);
- DisplayArea<WindowContainer> ime = new DisplayArea<>(wms, ABOVE_TASKS, "Ime");
+ DisplayArea.Tokens ime = new DisplayArea.Tokens(wms, ABOVE_TASKS, "Ime");
DisplayContent displayContent = mock(DisplayContent.class);
doReturn(true).when(displayContent).isTrusted();
mTaskDisplayArea1 = new TaskDisplayArea(displayContent, wms, "Tasks1",
@@ -143,7 +143,7 @@ public class DisplayAreaPolicyTests {
FEATURE_VENDOR_FIRST + 5);
final TaskDisplayArea taskDisplayArea5 = new TaskDisplayArea(displayContent, wms, "Tasks5",
FEATURE_VENDOR_FIRST + 6);
- final DisplayArea<WindowContainer> ime = new DisplayArea<>(wms, ABOVE_TASKS, "Ime");
+ final DisplayArea.Tokens ime = new DisplayArea.Tokens(wms, ABOVE_TASKS, "Ime");
final DisplayAreaPolicy policy = new DisplayAreaPolicyBuilder()
.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
.setImeContainer(ime)
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java
index 351426ae78b2..2d289808dd26 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java
@@ -81,7 +81,7 @@ public class DisplayAreaProviderTest {
@Override
public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content,
- RootDisplayArea root, DisplayArea<? extends WindowContainer> imeContainer) {
+ RootDisplayArea root, DisplayArea.Tokens imeContainer) {
throw new RuntimeException("test stub");
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 554160ccbb82..7c4f7db48022 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -16,7 +16,9 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -28,7 +30,6 @@ import static org.junit.Assert.assertTrue;
import android.annotation.Nullable;
import android.platform.test.annotations.Presubmit;
import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
import android.view.DisplayAddress;
@@ -69,7 +70,8 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
- private TestStorage mBaseSettingsStorage;
+ private TestStorage mDefaultVendorSettingsStorage;
+ private TestStorage mSecondaryVendorSettingsStorage;
private TestStorage mOverrideSettingsStorage;
private DisplayContent mPrimaryDisplay;
@@ -79,7 +81,8 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
public void setUp() throws Exception {
deleteRecursively(TEST_FOLDER);
- mBaseSettingsStorage = new TestStorage();
+ mDefaultVendorSettingsStorage = new TestStorage();
+ mSecondaryVendorSettingsStorage = new TestStorage();
mOverrideSettingsStorage = new TestStorage();
mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
@@ -122,7 +125,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
// Update settings with new value, should trigger write to injector.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
- mBaseSettingsStorage, mOverrideSettingsStorage);
+ mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
SettingsEntry overrideSettings = provider.getOverrideSettings(mPrimaryDisplayInfo);
overrideSettings.mForcedDensity = 200;
provider.updateOverrideSettings(mPrimaryDisplayInfo, overrideSettings);
@@ -162,12 +165,55 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
}
@Test
+ public void testReadingDisplaySettingsFromStorage_secondayVendorDisplaySettingsLocation() {
+ final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
+ prepareSecondaryDisplaySettings(displayIdentifier);
+
+ final DisplayWindowSettingsProvider provider =
+ new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage,
+ mOverrideSettingsStorage);
+
+ // Expected settings should be empty because the default is to read from the primary vendor
+ // settings location.
+ SettingsEntry expectedSettings = new SettingsEntry();
+ assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo()));
+
+ // Now switch to secondary vendor settings and assert proper settings.
+ provider.setBaseSettingsStorage(mSecondaryVendorSettingsStorage);
+ expectedSettings.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+ assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo()));
+
+ // Switch back to primary and assert settings are empty again.
+ provider.setBaseSettingsStorage(mDefaultVendorSettingsStorage);
+ expectedSettings.mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo()));
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage_overrideSettingsTakePrecedenceOverVendor() {
+ final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
+ prepareOverrideDisplaySettings(displayIdentifier);
+ prepareSecondaryDisplaySettings(displayIdentifier);
+
+ final DisplayWindowSettingsProvider provider =
+ new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage,
+ mOverrideSettingsStorage);
+ provider.setBaseSettingsStorage(mSecondaryVendorSettingsStorage);
+
+ // The windowing mode should be set to WINDOWING_MODE_PINNED because the override settings
+ // take precedence over the vendor provided settings.
+ SettingsEntry expectedSettings = new SettingsEntry();
+ expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+ assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo()));
+ }
+
+ @Test
public void testWritingDisplaySettingsToStorage() throws Exception {
final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
// Write some settings to storage.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
- mBaseSettingsStorage, mOverrideSettingsStorage);
+ mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
overrideSettings.mShouldShowSystemDecors = true;
overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
@@ -195,7 +241,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
// Write some settings to storage.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
- mBaseSettingsStorage, mOverrideSettingsStorage);
+ mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
overrideSettings.mShouldShowSystemDecors = true;
overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
@@ -236,10 +282,29 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
mOverrideSettingsStorage.setReadStream(is);
}
+ /**
+ * Prepares display settings and stores in {@link #mSecondaryVendorSettingsStorage}. Uses
+ * provided display identifier and stores windowingMode=WINDOWING_MODE_FULLSCREEN.
+ */
+ private void prepareSecondaryDisplaySettings(String displayIdentifier) {
+ String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<display-settings>\n";
+ if (displayIdentifier != null) {
+ contents += " <display\n"
+ + " name=\"" + displayIdentifier + "\"\n"
+ + " windowingMode=\"" + WINDOWING_MODE_FULLSCREEN + "\"/>\n";
+ }
+ contents += "</display-settings>\n";
+
+ final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+ mSecondaryVendorSettingsStorage.setReadStream(is);
+ }
+
private void readAndAssertExpectedSettings(DisplayContent displayContent,
SettingsEntry expectedSettings) {
final DisplayWindowSettingsProvider provider =
- new DisplayWindowSettingsProvider(mBaseSettingsStorage, mOverrideSettingsStorage);
+ new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage,
+ mOverrideSettingsStorage);
assertEquals(expectedSettings, provider.getSettings(displayContent.getDisplayInfo()));
}
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 536ef48065a5..83e3d22345e1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -299,6 +299,7 @@ public class SystemServicesTestRule implements TestRule {
doNothing().when(mWmService.mRoot).ensureActivitiesVisible(any(),
anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
spyOn(mWmService.mDisplayWindowSettings);
+ spyOn(mWmService.mDisplayWindowSettingsProvider);
// Setup factory classes to prevent calls to native code.
mTransaction = spy(StubTransaction.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
index ba144dd367d9..4e1b3510bdaa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
@@ -20,7 +20,7 @@ import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDO
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
-import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS;
+import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -58,8 +58,8 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
@Test
public void testForceDesktopModeOnExternalDisplays() {
- try (SettingsSession forceDesktopModeSession = new
- SettingsSession(DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS)) {
+ try (BoolSettingsSession forceDesktopModeSession = new
+ BoolSettingsSession(DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS)) {
final boolean forceDesktopMode = !forceDesktopModeSession.getSetting();
final Uri forceDesktopModeUri = forceDesktopModeSession.setSetting(forceDesktopMode);
mWm.mSettingsObserver.onChange(false, forceDesktopModeUri);
@@ -70,8 +70,8 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
@Test
public void testFreeformWindow() {
- try (SettingsSession freeformWindowSession = new
- SettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) {
+ try (BoolSettingsSession freeformWindowSession = new
+ BoolSettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) {
final boolean curFreeformWindow = freeformWindowSession.getSetting();
final boolean newFreeformWindow = !curFreeformWindow;
final Uri freeformWindowUri = freeformWindowSession.setSetting(newFreeformWindow);
@@ -84,8 +84,8 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
@Test
public void testFreeformWindow_valueChanged_updatesDisplaySettings() {
- try (SettingsSession freeformWindowSession = new
- SettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) {
+ try (BoolSettingsSession freeformWindowSession = new
+ BoolSettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) {
final boolean curFreeformWindow = freeformWindowSession.getSetting();
final boolean newFreeformWindow = !curFreeformWindow;
final Uri freeformWindowUri = freeformWindowSession.setSetting(newFreeformWindow);
@@ -106,8 +106,8 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
@Test
public void testForceResizableMode() {
- try (SettingsSession forceResizableSession = new
- SettingsSession(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES)) {
+ try (BoolSettingsSession forceResizableSession = new
+ BoolSettingsSession(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES)) {
final boolean forceResizableMode = !forceResizableSession.getSetting();
final Uri forceResizableUri = forceResizableSession.setSetting(forceResizableMode);
@@ -119,8 +119,8 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
@Test
public void testEnableSizeCompatFreeform() {
- try (SettingsSession enableSizeCompatFreeformSession = new
- SettingsSession(DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM)) {
+ try (BoolSettingsSession enableSizeCompatFreeformSession = new
+ BoolSettingsSession(DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM)) {
final boolean enableSizeCompatFreeform =
!enableSizeCompatFreeformSession.getSetting();
final Uri enableSizeCompatFreeformUri =
@@ -132,21 +132,22 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
}
@Test
- public void testEnabledIgnoreVendorDisplaySettings() {
- try (SettingsSession ignoreVendorDisplaySettingsSession = new
- SettingsSession(DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS)) {
- final boolean ignoreVendorDisplaySettings =
- !ignoreVendorDisplaySettingsSession.getSetting();
- final Uri ignoreVendorDisplaySettingUri =
- ignoreVendorDisplaySettingsSession.setSetting(ignoreVendorDisplaySettings);
+ public void testChangeBaseDisplaySettingsPath() {
+ try (StringSettingsSession baseDisplaySettingsPathSession = new
+ StringSettingsSession(DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH)) {
+ final String path = baseDisplaySettingsPathSession.getSetting() + "-test";
+ final Uri baseDisplaySettingsPathUri = baseDisplaySettingsPathSession.setSetting(path);
clearInvocations(mWm.mRoot);
clearInvocations(mWm.mDisplayWindowSettings);
+ clearInvocations(mWm.mDisplayWindowSettingsProvider);
- mWm.mSettingsObserver.onChange(false /* selfChange */, ignoreVendorDisplaySettingUri);
+ mWm.mSettingsObserver.onChange(false /* selfChange */, baseDisplaySettingsPathUri);
- assertEquals(mWm.mDisplayWindowSettingsProvider.getVendorSettingsIgnored(),
- ignoreVendorDisplaySettings);
+ ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class);
+ verify(mWm.mDisplayWindowSettingsProvider).setBaseSettingsFilePath(
+ pathCaptor.capture());
+ assertEquals(path, pathCaptor.getValue());
ArgumentCaptor<DisplayContent> captor =
ArgumentCaptor.forClass(DisplayContent.class);
@@ -161,14 +162,14 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
}
}
- private class SettingsSession implements AutoCloseable {
+ private class BoolSettingsSession implements AutoCloseable {
private static final int SETTING_VALUE_OFF = 0;
private static final int SETTING_VALUE_ON = 1;
private final String mSettingName;
private final int mInitialValue;
- SettingsSession(String name) {
+ BoolSettingsSession(String name) {
mSettingName = name;
mInitialValue = getSetting() ? SETTING_VALUE_ON : SETTING_VALUE_OFF;
}
@@ -192,4 +193,32 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
setSetting(mInitialValue == SETTING_VALUE_ON);
}
}
+
+ private class StringSettingsSession implements AutoCloseable {
+ private final String mSettingName;
+ private final String mInitialValue;
+
+ StringSettingsSession(String name) {
+ mSettingName = name;
+ mInitialValue = getSetting();
+ }
+
+ String getSetting() {
+ return Settings.Global.getString(getContentResolver(), mSettingName);
+ }
+
+ Uri setSetting(String value) {
+ Settings.Global.putString(getContentResolver(), mSettingName, value);
+ return Settings.Global.getUriFor(mSettingName);
+ }
+
+ private ContentResolver getContentResolver() {
+ return getInstrumentation().getTargetContext().getContentResolver();
+ }
+
+ @Override
+ public void close() {
+ setSetting(mInitialValue);
+ }
+ }
}
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 4c49c6e4f0b9..14a62d1a4ff0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -27,6 +27,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.os.Process.SYSTEM_UID;
import static android.view.View.VISIBLE;
+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.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -40,8 +42,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -64,7 +64,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Bundle;
@@ -831,13 +830,14 @@ class WindowTestsBase extends SystemServiceTestsBase {
if (mLaunchTaskBehind) {
options = ActivityOptions.makeTaskLaunchBehind();
}
+ final ActivityRecord activity = new ActivityRecord.Builder(mService)
+ .setLaunchedFromPid(mLaunchedFromPid)
+ .setLaunchedFromUid(mLaunchedFromUid)
+ .setIntent(intent)
+ .setActivityInfo(aInfo)
+ .setActivityOptions(options)
+ .build();
- final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
- mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */,
- null, null, intent, null, aInfo /*aInfo*/, new Configuration(),
- null /* resultTo */, null /* resultWho */, 0 /* reqCode */,
- false /*componentSpecified*/, false /* rootVoiceInteraction */,
- mService.mTaskSupervisor, options, null /* sourceRecord */);
spyOn(activity);
if (mTask != null) {
// fullscreen value is normally read from resources in ctor, so for testing we need
diff --git a/telecomm/java/android/telecom/BluetoothCallQualityReport.java b/telecomm/java/android/telecom/BluetoothCallQualityReport.java
new file mode 100644
index 000000000000..10339a818205
--- /dev/null
+++ b/telecomm/java/android/telecom/BluetoothCallQualityReport.java
@@ -0,0 +1,256 @@
+/*
+ * 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.telecom;
+
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class represents the quality report that bluetooth framework sends
+ * whenever there's a bad voice quality is detected from their side.
+ * It is sent as part of a call event via {@link Call#sendCallEvent(String, Bundle)}
+ * associated with extra EXTRA_BLUETOOTH_CALL_QUALITY_REPORT.
+ * Note that this report will be sent only during an active voice/voip call.
+ * @hide
+ */
+@SystemApi
+public final class BluetoothCallQualityReport implements Parcelable {
+
+ /**
+ * Event that is sent via {@link Call#sendCallEvent(String, Bundle)} for a call quality report
+ */
+ public static final String EVENT_BLUETOOTH_CALL_QUALITY_REPORT =
+ "android.telecom.event.BLUETOOTH_CALL_QUALITY_REPORT";
+
+ /**
+ * Extra key sent with {@link Call#sendCallEvent(String, Bundle)}
+ */
+ public static final String EXTRA_BLUETOOTH_CALL_QUALITY_REPORT =
+ "android.telecom.extra.BLUETOOTH_CALL_QUALITY_REPORT";
+
+ private final long mSentTimestampMillis;
+ private final boolean mChoppyVoice;
+ private final int mRssiDbm;
+ private final int mSnrDb;
+ private final int mRetransmittedPacketsCount;
+ private final int mPacketsNotReceivedCount;
+ private final int mNegativeAcknowledgementCount;
+
+ /**
+ * @return Time in milliseconds since the epoch. Designates when report was sent.
+ * Used to determine whether this report arrived too late to be useful.
+ */
+ public @ElapsedRealtimeLong long getSentTimestampMillis() {
+ return mSentTimestampMillis;
+ }
+
+ /**
+ * @return {@code true} if bluetooth hardware detects voice is choppy
+ */
+ public boolean isChoppyVoice() {
+ return mChoppyVoice;
+ }
+
+ /**
+ * @return Received Signal Strength Indication (RSSI) value in dBm.
+ * This value shall be an absolute received signal strength value.
+ */
+ public @IntRange(from = -127, to = 20) int getRssiDbm() {
+ return mRssiDbm;
+ }
+
+ /**
+ * @return Signal-to-Noise Ratio (SNR) value in dB.
+ * The controller shall provide the average SNR of all the channels currently used by the link.
+ */
+ public int getSnrDb() {
+ return mSnrDb;
+ }
+
+ /**
+ * @return The number of retransmissions since the last event.
+ * This count shall be reset after it is reported.
+ */
+ public @IntRange(from = 0) int getRetransmittedPacketsCount() {
+ return mRetransmittedPacketsCount;
+ }
+
+ /**
+ * @return No RX count since the last event.
+ * The count increases when no packet is received at the scheduled time slot or the received
+ * packet is corrupted.
+ * This count shall be reset after it is reported.
+ */
+ public @IntRange(from = 0) int getPacketsNotReceivedCount() {
+ return mPacketsNotReceivedCount;
+ }
+
+ /**
+ * @return NAK (Negative Acknowledge) count since the last event.
+ * This count shall be reset after it is reported.
+ */
+ public @IntRange(from = 0) int getNegativeAcknowledgementCount() {
+ return mNegativeAcknowledgementCount;
+ }
+
+ //
+ // Parcelable implementation
+ //
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeLong(mSentTimestampMillis);
+ out.writeBoolean(mChoppyVoice);
+ out.writeInt(mRssiDbm);
+ out.writeInt(mSnrDb);
+ out.writeInt(mRetransmittedPacketsCount);
+ out.writeInt(mPacketsNotReceivedCount);
+ out.writeInt(mNegativeAcknowledgementCount);
+ }
+
+ public static final @android.annotation.NonNull Creator<BluetoothCallQualityReport> CREATOR =
+ new Creator<BluetoothCallQualityReport>() {
+ @Override
+ public BluetoothCallQualityReport createFromParcel(Parcel in) {
+ return new BluetoothCallQualityReport(in);
+ }
+
+ @Override
+ public BluetoothCallQualityReport[] newArray(int size) {
+ return new BluetoothCallQualityReport[size];
+ }
+ };
+
+ /**
+ * Builder class for {@link ConnectionRequest}
+ */
+ public static final class Builder {
+ private long mSentTimestampMillis;
+ private boolean mChoppyVoice;
+ private int mRssiDbm;
+ private int mSnrDb;
+ private int mRetransmittedPacketsCount;
+ private int mPacketsNotReceivedCount;
+ private int mNegativeAcknowledgementCount;
+
+ public Builder() { }
+
+ /**
+ * Set the time when report was sent in milliseconds since the epoch.
+ * @param sentTimestampMillis
+ */
+ public @NonNull Builder setSentTimestampMillis(long sentTimestampMillis) {
+ mSentTimestampMillis = sentTimestampMillis;
+ return this;
+ }
+
+ /**
+ * Set if bluetooth hardware detects voice is choppy
+ * @param choppyVoice
+ */
+ public @NonNull Builder setChoppyVoice(boolean choppyVoice) {
+ mChoppyVoice = choppyVoice;
+ return this;
+ }
+
+ /**
+ * Set Received Signal Strength Indication (RSSI) value in dBm.
+ * @param rssiDbm
+ */
+ public @NonNull Builder setRssiDbm(int rssiDbm) {
+ mRssiDbm = rssiDbm;
+ return this;
+ }
+
+ /**
+ * Set Signal-to-Noise Ratio (SNR) value in dB.
+ * @param snrDb
+ */
+ public @NonNull Builder setSnrDb(int snrDb) {
+ mSnrDb = snrDb;
+ return this;
+ }
+
+ /**
+ * Set The number of retransmissions since the last event.
+ * @param retransmittedPacketsCount
+ */
+ public @NonNull Builder setRetransmittedPacketsCount(
+ int retransmittedPacketsCount) {
+ mRetransmittedPacketsCount = retransmittedPacketsCount;
+ return this;
+ }
+
+ /**
+ * Set No RX count since the last event.
+ * @param packetsNotReceivedCount
+ */
+ public @NonNull Builder setPacketsNotReceivedCount(
+ int packetsNotReceivedCount) {
+ mPacketsNotReceivedCount = packetsNotReceivedCount;
+ return this;
+ }
+
+ /**
+ * Set NAK (Negative Acknowledge) count since the last event.
+ * @param negativeAcknowledgementCount
+ */
+ public @NonNull Builder setNegativeAcknowledgementCount(
+ int negativeAcknowledgementCount) {
+ mNegativeAcknowledgementCount = negativeAcknowledgementCount;
+ return this;
+ }
+
+ /**
+ * Build the {@link BluetoothCallQualityReport}
+ * @return Result of the builder
+ */
+ public @NonNull BluetoothCallQualityReport build() {
+ return new BluetoothCallQualityReport(this);
+ }
+ }
+
+ private BluetoothCallQualityReport(Parcel in) {
+ mSentTimestampMillis = in.readLong();
+ mChoppyVoice = in.readBoolean();
+ mRssiDbm = in.readInt();
+ mSnrDb = in.readInt();
+ mRetransmittedPacketsCount = in.readInt();
+ mPacketsNotReceivedCount = in.readInt();
+ mNegativeAcknowledgementCount = in.readInt();
+ }
+
+ private BluetoothCallQualityReport(Builder builder) {
+ mSentTimestampMillis = builder.mSentTimestampMillis;
+ mChoppyVoice = builder.mChoppyVoice;
+ mRssiDbm = builder.mRssiDbm;
+ mSnrDb = builder.mSnrDb;
+ mRetransmittedPacketsCount = builder.mRetransmittedPacketsCount;
+ mPacketsNotReceivedCount = builder.mPacketsNotReceivedCount;
+ mNegativeAcknowledgementCount = builder.mNegativeAcknowledgementCount;
+ }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index baee4736b527..0939bf02a039 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4012,6 +4012,17 @@ public class CarrierConfigManager {
"default_preferred_apn_name_string";
/**
+ * Indicates if the carrier supports call composer.
+ */
+ public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool";
+
+ /**
+ * Indicates the carrier server url that serves the call composer picture.
+ */
+ public static final String KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING =
+ "call_composer_picture_server_url_string";
+
+ /**
* For Android 11, provide a temporary solution for OEMs to use the lower of the two MTU values
* for IPv4 and IPv6 if both are sent.
* TODO: remove in later release
@@ -4563,6 +4574,8 @@ public class CarrierConfigManager {
sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
+ sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false);
+ sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, "");
sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d963970a3d2b..886ec33af2b8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -11694,18 +11694,6 @@ public class TelephonyManager {
}
/**
- * In this mode, modem will not send specified indications when screen is off.
- * @hide
- */
- public static final int INDICATION_UPDATE_MODE_NORMAL = 1;
-
- /**
- * In this mode, modem will still send specified indications when screen is off.
- * @hide
- */
- public static final int INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF = 2;
-
- /**
* The indication for signal strength update.
* @hide
*/
diff --git a/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
index 4deaba1b7a49..a14199365b07 100644
--- a/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
@@ -32,5 +32,5 @@ oneway interface ISubscribeResponseCallback {
void onNetworkResponse(int code, in String reason);
void onNotifyCapabilitiesUpdate(in List<String> pidfXmls);
void onResourceTerminated(in List<RcsContactTerminatedReason> uriTerminatedReason);
- void onTerminated(in String reason, in String retryAfter);
+ void onTerminated(in String reason, long retryAfterMilliseconds);
}
diff --git a/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
index 37588ed98585..1fb339c0cf89 100644
--- a/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
@@ -86,9 +86,9 @@ public class RcsSubscribeResponseAidlWrapper implements SubscribeResponseCallbac
}
@Override
- public void onTerminated(String reason, String retryAfter) throws ImsException {
+ public void onTerminated(String reason, long retryAfterMilliseconds) throws ImsException {
try {
- mResponseBinder.onTerminated(reason, retryAfter);
+ mResponseBinder.onTerminated(reason, retryAfterMilliseconds);
} catch (RemoteException e) {
}
}
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index e8234178be9d..9a3f592480d1 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -231,8 +231,9 @@ public class MmTelFeature extends ImsFeature {
* The capabilities that are used in MmTelFeature are defined as
* {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE},
* {@link MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
- * {@link MmTelCapabilities#CAPABILITY_TYPE_UT}, and
- * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}.
+ * {@link MmTelCapabilities#CAPABILITY_TYPE_UT},
+ * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}, and
+ * {@link MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER}.
*
* The capabilities of this MmTelFeature will be set by the framework.
*/
@@ -275,7 +276,8 @@ public class MmTelFeature extends ImsFeature {
CAPABILITY_TYPE_VOICE,
CAPABILITY_TYPE_VIDEO,
CAPABILITY_TYPE_UT,
- CAPABILITY_TYPE_SMS
+ CAPABILITY_TYPE_SMS,
+ CAPABILITY_TYPE_CALL_COMPOSER
})
@Retention(RetentionPolicy.SOURCE)
public @interface MmTelCapability {}
@@ -301,6 +303,11 @@ public class MmTelFeature extends ImsFeature {
public static final int CAPABILITY_TYPE_SMS = 1 << 3;
/**
+ * This MmTelFeature supports Call Composer (section 2.4 of RC.20)
+ */
+ public static final int CAPABILITY_TYPE_CALL_COMPOSER = 1 << 4;
+
+ /**
* @hide
*/
@Override
@@ -343,6 +350,8 @@ public class MmTelFeature extends ImsFeature {
builder.append(isCapable(CAPABILITY_TYPE_UT));
builder.append(" SMS: ");
builder.append(isCapable(CAPABILITY_TYPE_SMS));
+ builder.append(" CALL_COMPOSER: ");
+ builder.append(isCapable(CAPABILITY_TYPE_CALL_COMPOSER));
builder.append("]");
return builder.toString();
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index b5704bfb3569..3a0fb6edb2fb 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -250,7 +250,7 @@ public class RcsCapabilityExchangeImplBase {
* This allows the framework to know that there will no longer be any
* capability updates for the requested operationToken.
*/
- void onTerminated(String reason, String retryAfter) throws ImsException;
+ void onTerminated(String reason, long retryAfterMilliseconds) throws ImsException;
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index a20f96d17278..67deca4fe387 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.close
+import androidx.test.filters.FlakyTest
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -54,6 +55,7 @@ import org.junit.runners.Parameterized
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 174635878)
class CloseAppBackButtonTest(
testName: String,
flickerSpec: Flicker
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 4bbb38c4d71a..252ce2a32bf0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.close
+import androidx.test.filters.FlakyTest
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -54,6 +55,7 @@ import org.junit.runners.Parameterized
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 174635878)
class CloseAppHomeButtonTest(
testName: String,
flickerSpec: Flicker
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index a8aab2a899fb..a72b07c45dd8 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -6,6 +6,7 @@ android_test {
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
+ "truth-prebuilt",
"ub-uiautomator",
],
test_suites: ["device-tests"],
diff --git a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
new file mode 100644
index 000000000000..f919a3eaf271
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.input
+
+import android.graphics.FrameInfo
+import android.os.SystemClock
+import android.view.ViewFrameInfo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+class ViewFrameInfoTest {
+ companion object {
+ private const val TAG = "ViewFrameInfoTest"
+ }
+ private val mViewFrameInfo = ViewFrameInfo()
+ private var mTimeStarted: Long = 0
+
+ @Before
+ fun setUp() {
+ mViewFrameInfo.reset()
+ mViewFrameInfo.updateOldestInputEvent(10)
+ mViewFrameInfo.updateNewestInputEvent(20)
+ mViewFrameInfo.flags = mViewFrameInfo.flags or FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED
+ mTimeStarted = SystemClock.uptimeNanos()
+ mViewFrameInfo.markDrawStart()
+ }
+
+ @Test
+ fun testPopulateFields() {
+ assertThat(mViewFrameInfo.drawStart).isGreaterThan(mTimeStarted)
+ assertThat(mViewFrameInfo.oldestInputEventTime).isEqualTo(10)
+ assertThat(mViewFrameInfo.newestInputEventTime).isEqualTo(20)
+ assertThat(mViewFrameInfo.flags).isEqualTo(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED)
+ }
+
+ @Test
+ fun testReset() {
+ mViewFrameInfo.reset()
+ // Ensure that the original object is reset correctly
+ assertThat(mViewFrameInfo.drawStart).isEqualTo(0)
+ assertThat(mViewFrameInfo.oldestInputEventTime).isEqualTo(0)
+ assertThat(mViewFrameInfo.newestInputEventTime).isEqualTo(0)
+ assertThat(mViewFrameInfo.flags).isEqualTo(0)
+ }
+
+ @Test
+ fun testUpdateFrameInfoFromViewFrameInfo() {
+ val frameInfo = FrameInfo()
+ // By default, all values should be zero
+ assertThat(frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT]).isEqualTo(0)
+ assertThat(frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT]).isEqualTo(0)
+ assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(0)
+ assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isEqualTo(0)
+
+ // The values inside FrameInfo should match those from ViewFrameInfo after we update them
+ mViewFrameInfo.populateFrameInfo(frameInfo)
+ assertThat(frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT]).isEqualTo(10)
+ assertThat(frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT]).isEqualTo(20)
+ assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(
+ FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED)
+ assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isGreaterThan(mTimeStarted)
+ }
+} \ No newline at end of file
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index f55d4d474bfb..3a40696d1add 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -31,7 +31,6 @@ java_test_host {
"testng",
"compatibility-tradefed",
"frameworks-base-hostutils",
- "module_test_util",
"cts-install-lib-host",
],
data: [
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 27ccbc78cf96..9e1ea2e04528 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -29,7 +29,6 @@ import android.cts.install.lib.host.InstallUtilsHost;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
import com.android.tests.rollback.host.AbandonSessionsRule;
-import com.android.tests.util.ModuleTestUtils;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -60,7 +59,6 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
private static final String APK_A = "TestAppAv1.apk";
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
- private final ModuleTestUtils mTestUtils = new ModuleTestUtils(this);
private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
/**
@@ -161,7 +159,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ final File apexFile = mHostUtils.getTestFile(SHIM_V2);
final String output = getDevice().executeAdbCommand("install", "--staged",
"--staged-ready-timeout", "60000", apexFile.getAbsolutePath());
assertThat(output).contains("Reboot device to apply staged session");
@@ -176,7 +174,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ final File apexFile = mHostUtils.getTestFile(SHIM_V2);
final String output = getDevice().executeAdbCommand("install", "--staged",
apexFile.getAbsolutePath());
assertThat(output).contains("Reboot device to apply staged session");
@@ -191,7 +189,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ final File apexFile = mHostUtils.getTestFile(SHIM_V2);
final String output = getDevice().executeAdbCommand("install", "--staged",
"--staged-ready-timeout", "0", apexFile.getAbsolutePath());
assertThat(output).doesNotContain("Reboot device to apply staged session");
@@ -207,7 +205,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ final File apexFile = mHostUtils.getTestFile(SHIM_V2);
String output = getDevice().executeAdbCommand("install", "--staged",
"--enable-rollback", apexFile.getAbsolutePath());
assertThat(output).contains("Reboot device to apply staged session");
@@ -224,8 +222,8 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- final File apexFile = mTestUtils.getTestFile(SHIM_V2);
- final File apkFile = mTestUtils.getTestFile(APK_A);
+ final File apexFile = mHostUtils.getTestFile(SHIM_V2);
+ final File apkFile = mHostUtils.getTestFile(APK_A);
final String output = getDevice().executeAdbCommand("install-multi-package",
apexFile.getAbsolutePath(), apkFile.getAbsolutePath());
assertThat(output).contains("Created parent session");
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ba87dc50e246..5d4573716145 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -56,8 +56,10 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
@@ -5398,6 +5400,106 @@ public class ConnectivityServiceTest {
}
@Test
+ public void testApplyUnderlyingCapabilities() throws Exception {
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mCellNetworkAgent.connect(false /* validated */);
+ mWiFiNetworkAgent.connect(false /* validated */);
+
+ final NetworkCapabilities cellNc = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .setLinkDownstreamBandwidthKbps(10);
+ final NetworkCapabilities wifiNc = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .addCapability(NET_CAPABILITY_NOT_ROAMING)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .setLinkUpstreamBandwidthKbps(20);
+ mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
+ mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
+ waitForIdle();
+
+ final Network mobile = mCellNetworkAgent.getNetwork();
+ final Network wifi = mWiFiNetworkAgent.getNetwork();
+
+ final NetworkCapabilities initialCaps = new NetworkCapabilities();
+ initialCaps.addCapability(NET_CAPABILITY_INTERNET);
+ initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN);
+
+ final NetworkCapabilities withNoUnderlying = new NetworkCapabilities();
+ withNoUnderlying.addCapability(NET_CAPABILITY_INTERNET);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_CONGESTED);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ withNoUnderlying.addTransportType(TRANSPORT_VPN);
+ withNoUnderlying.removeCapability(NET_CAPABILITY_NOT_VPN);
+
+ final NetworkCapabilities withMobileUnderlying = new NetworkCapabilities(withNoUnderlying);
+ withMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
+ withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ withMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
+
+ final NetworkCapabilities withWifiUnderlying = new NetworkCapabilities(withNoUnderlying);
+ withWifiUnderlying.addTransportType(TRANSPORT_WIFI);
+ withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
+ withWifiUnderlying.setLinkUpstreamBandwidthKbps(20);
+
+ final NetworkCapabilities withWifiAndMobileUnderlying =
+ new NetworkCapabilities(withNoUnderlying);
+ withWifiAndMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
+ withWifiAndMobileUnderlying.addTransportType(TRANSPORT_WIFI);
+ withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
+ withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
+ withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20);
+
+ NetworkCapabilities caps = new NetworkCapabilities(initialCaps);
+ final boolean notDeclaredMetered = false;
+ mService.applyUnderlyingCapabilities(new Network[]{}, caps, notDeclaredMetered);
+ assertEquals(withNoUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null}, caps, notDeclaredMetered);
+ assertEquals(withNoUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{mobile}, caps, notDeclaredMetered);
+ assertEquals(withMobileUnderlying, caps);
+
+ mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, notDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+
+ final boolean isDeclaredMetered = true;
+ withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, isDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, caps, isDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
+ caps, notDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
+ caps, notDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ mService.applyUnderlyingCapabilities(null, caps, notDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+ }
+
+ @Test
public void testVpnConnectDisconnectUnderlyingNetwork() throws Exception {
final TestNetworkCallback callback = new TestNetworkCallback();
final NetworkRequest request = new NetworkRequest.Builder()
@@ -5947,17 +6049,28 @@ public class ConnectivityServiceTest {
&& caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_WIFI));
+ // Change the VPN's capabilities somehow (specifically, disconnect wifi).
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ callback.expectCapabilitiesThat(mMockVpn, (caps)
+ -> caps.getUids().size() == 2
+ && caps.getUids().contains(new UidRange(uid, uid))
+ && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+ && caps.hasTransport(TRANSPORT_VPN)
+ && !caps.hasTransport(TRANSPORT_WIFI));
+
// Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
- // Expect that the VPN gains the UID range for the restricted user.
+ // Expect that the VPN gains the UID range for the restricted user, and that the capability
+ // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 1
&& caps.getUids().contains(new UidRange(uid, uid))
&& caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_WIFI));
+ && !caps.hasTransport(TRANSPORT_WIFI));
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index d0db55f2bb13..337507ac1d46 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -21,15 +21,6 @@ import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
import static android.net.ConnectivityManager.NetworkCallback;
-import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -621,102 +612,6 @@ public class VpnTest {
order.verify(mNotificationManager).cancel(anyString(), anyInt());
}
- @Test
- public void testCapabilities() {
- setMockedUsers(primaryUser);
-
- final Network mobile = new Network(1);
- final Network wifi = new Network(2);
-
- final Map<Network, NetworkCapabilities> networks = new HashMap<>();
- networks.put(
- mobile,
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .setLinkDownstreamBandwidthKbps(10));
- networks.put(
- wifi,
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
- .setLinkUpstreamBandwidthKbps(20));
- setMockedNetworks(networks);
-
- final NetworkCapabilities caps = new NetworkCapabilities();
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager,
- new Network[] {mobile},
- caps,
- false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager,
- new Network[] {mobile, wifi},
- caps,
- false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- }
-
/**
* The profile name should NOT change between releases for backwards compatibility
*
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 52e3840c126e..7a9ca6012be5 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -147,7 +147,7 @@ java_sdk_library {
// defaults for tests that need to build against framework-wifi's @hide APIs
java_defaults {
name: "framework-wifi-test-defaults",
- sdk_version: "core_platform", // tests can use @CorePlatformApi's
+ sdk_version: "core_current",
libs: [
// order matters: classes in framework-wifi are resolved before framework, meaning
// @hide APIs in framework-wifi are resolved before @SystemApi stubs in framework
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
index 7272e146f4f8..7eba0a73be31 100644
--- a/wifi/tests/Android.bp
+++ b/wifi/tests/Android.bp
@@ -20,6 +20,9 @@ android_test {
defaults: ["framework-wifi-test-defaults"],
+ min_sdk_version: "30",
+ target_sdk_version: "30",
+
srcs: ["**/*.java"],
jacoco: {